标签: separation-of-concerns

如何将数据验证与我的简单域对象(PO​​CO)分开?

这个问题与语言无关,但我是C#家伙所以我使用术语POCO来表示一个只能预先形成数据存储的对象,通常使用getter和setter字段.

我只是将我的领域模型重新设计成超级PCOO,并且对于如何确保属性值在域中有意义而留下了一些问题.

例如,服务的EndDate不应超过服务所在合同的EndDate.但是,将检查放入Service.EndDate设置器似乎违反了SOLID,更不用说随着需要完成的验证数量增加,我的POCO类将变得混乱.

我有一些解决方案(将在答案中发布),但它们有其缺点,我想知道解决这一难题的最佳方法是什么?

language-agnostic separation-of-concerns solid-principles modular-design

7
推荐指数
1
解决办法
1806
查看次数

Asp.Net MVC行动 - 关注点分离/单一责任原则

在计算机科学中,我们被教导每种方法应该只做一件事,一件事.我有点困惑,然后我们看到MVC行为如下所示作为良好实践的例子:

    [AcceptVerbs(HttpVerbs.Post), Authorize]
    public ActionResult Edit(int id, FormCollection collection) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (!dinner.IsHostedBy(User.Identity.Name))
            return View("InvalidOwner");

        try {
            UpdateModel(dinner);

            dinnerRepository.Save();

            return RedirectToAction("Details", new { id=dinner.DinnerID });
        }
        catch {
            ModelState.AddModelErrors(dinner.GetRuleViolations());

            return View(new DinnerFormViewModel(dinner));
        }
    }
Run Code Online (Sandbox Code Playgroud)

基本上这段代码提供了很多功能:

  1. 定义如何访问Action - 仅限Post
  2. 定义谁可以访问Action - Authorize
  3. 访问持久性机制 - dinnerRepository
  4. 访问状态信息 - (User.Identity.Name)
  5. 将NameValueCollection转换为强类型对象 - UpdateModel()
  6. 为每个指定3个可能的ActionResults和内容--InvalidOwner/Details/Edit视图

对我来说,这似乎对一种方法的责任太多了.它也是一个相当简单的动作,即它不处理常见的情况,如:

  1. 检查业务规则 - "永远不要信任用户输入"
  2. 导航路径 - 成功保存后始终返回"详细信息"
  3. 不同的返回类型 - 有人想从网格中调用"编辑"并需要一个JsonResult吗?
  4. 更好的错误处理 - 如果在GetDinner(id)期间无法访问数据库,则为YSOD
  5. 构建其他视图数据 - 用于下拉列表的SelectLists

不要太提及围绕这种方法所需的测试量,即FormCollection/UserIdentity/Authorization Provider/Repository/etc的模拟/伪造.

我的问题是我们如何避免在控制器操作中塞入如此多的东西?

我倾向于认为"意见"是一个伟大的概念,尤其是"Thunderdome Principle".虽然我非常尊重参与构建FubuMVC的人 …

asp.net-mvc separation-of-concerns

7
推荐指数
1
解决办法
1965
查看次数

接近重构

我有一个以数据为中心的应用程序,用Python/PyQt编写.我打算做一些重构来真正将UI与核心分开,主要是因为还没有任何真正的测试,而且显然必须改变.

已经存在一些分离,我认为我已经以正确的方式做了很多事情,但它远非完美.两个例子,告诉你什么样的事情困扰着我:

  • 当用户右键单击数据对象的表示时,弹出的上下文菜单由数据对象创建,尽管此数据对象(实质上是数据库行的ORM表示)应该与UI无关.

  • 当某些内容被写入数据库但写入失败时(例如,因为数据库记录被其他用户锁定),会向用户呈现经典的"重试/中止"消息框.此对话框由数据提供程序*创建,但提供程序显然不应具有任何UI功能.显然,提供者可以提出异常或以其他方式指示失败,并且UI可以捕获并相应地采取行动.

    *这是我用于对象的词,它基本上代表数据库表并在其数据对象和数据库引擎之间进行调解; 我不确定这是否通常被称为"提供者"

我没有测试经验,所以我不容易"感觉"可测性问题等,但在我开始之前,必须进行一些重组.

没有复杂的业务逻辑(它主要只是CRU D,是的,即使没有D),这将比重写更重组,所以我并不真正关心引入这个问题中讨论的回归错误.

我的计划是开始重构这个想法,因为UI部分很容易被删除,例如,由Web前端或基于文本的界面而不是Qt界面替换.另一方面,Qt本身仍将被核心使用,因为信号/插槽机制在很多地方使用,例如数据对象发出changed信号来指示,你知道什么.

所以,我的问题:这是一种提高可测试性和可维护性的可行方法吗?还有其他任何评论,特别是考虑到Python吗?

python refactoring qt unit-testing separation-of-concerns

7
推荐指数
2
解决办法
723
查看次数

MVC和NOSQL:将View Model直接保存到MongoDB?

据我所知,MVC中关注点分离的"正确"结构是为您的视图构建视图模型,并为您选择的存储库中的数据模型提供独立的数据模型.我开始尝试使用MongoDB,并且我开始认为在使用无架构的NO-SQL样式数据库时这可能不适用.我想将此场景呈现给stackoverflow社区,看看每个人的想法是什么.我是MVC的新手,所以这对我来说很有意义,但也许我忽略了一些......

以下是我讨论的示例:当用户想要编辑他们的个人资料时,他们会转到UserEdit视图,该视图使用下面的UserEdit模型.

public class UserEditModel
{
    public string Username
    {
        get { return Info.Username; }
        set { Info.Username = value; }
    }

    [Required]
    [MembershipPassword]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [DisplayName("Confirm Password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

    [Required]
    [Email]
    public string Email { get; set; }

    public UserInfo Info { get; set; }
    public Dictionary<string, bool> Roles { get; set; }
}

public class …
Run Code Online (Sandbox Code Playgroud)

asp.net-mvc separation-of-concerns mongodb

7
推荐指数
2
解决办法
1666
查看次数

在哪里建立新的域名实体?控制器,存储库或映射器?

假设对于每个域实体,我都有一个为数据映射器提供API的存储库.例如,如果我有一个UserEntity,那么我会有一个UserRepository与UserMapper说话,以便在数据库中保存用户数据.

现在,假设一个表单在网页上提交,我的控制器知道它需要根据提交的信息创建一个新的UserEntity.

可以:

  1. 在那里做新的UserEntity(),并根据提交的表单数据运行所有必要的setter方法,然后将UserEntity传递给repo,后者将传递给mapper进行插入?

    控制器创建UserEntity => Repo => Mapper => DB

  2. 将表单数据转换为数组,并将其传递给UserRepository,然后UserRepository运行新的UserEntity()和setter,并将其传递给mapper进行插入?

    控制器传递用户数据=> Repo创建UserEntity => Mapper => DB

  3. 将数组传递给UserRepository,UserRepository将数组传递给映射器以获取新的UserEntity和插入?

    控制器传递用户数据=> Repo传递用户数据=> Mapper创建UserEntity => DB

谁负责管理对象的创建?

php instantiation separation-of-concerns

7
推荐指数
1
解决办法
533
查看次数

将域实体的可变属性存储为值对象是否可以?

我希望能够改变和传递我的UserEntity的某些部分,并且某些部分应该保持不变.

例如,我从不想改变我的UserEntity的id,但是电子邮件或密码之类的东西可能会经常更改,并且也可以被UserEntity之外的其他对象使用.

其中一个例子是创建UserEntity时.由于UserEntity在没有id的情况下不能存在,我的控制器可以创建一个UserData对象来标准化UserEntity属性.在映射器在db中创建实体之后,它将创建一个新的UserEntity并传​​入构造函数中的id和UserData对象.

当UserEntity需要电子邮件或密码等信息时,它只能查看其UserData.

看起来更便携,但这有点过分吗?有更好的解决方案吗?

注意

  • 我认为这可能是好的原因:可变字段的值需要标准化......有时这些字段需要在实体本身之外传递.例如,在创建实体之前.通过创建一个可以传递的值对象,我们提供了一个标准化的点,可以从任何地方分配这些值,以及可以在实体外部传递的东西.

  • 通过"标准化",我的意思是我的信息需要统一,无论它存在于何处.例如,email需要总是n长度和有效的格式,name总是需要n长度等.我的目标是,我希望能够在一个地方设置这些"规则"...并且因为这些UserEntity(可变的)的属性存在于实体本身之外,有时,它们可能在自己的值对象中独立存在.

php architecture separation-of-concerns

7
推荐指数
1
解决办法
251
查看次数

Ruby On Rails - 在控制器中使用关注点

可能的Noob警告: RoR的新功能

我试图在RoR中使用关注点.现在我只是写了一个非常简单的问题

#./app/controllers/concerns/foo.rb
module Foo
  extend ActiveSupport::Concern

  def somethingfoo
    puts "Ayyyy! Foo"
  end
end
Run Code Online (Sandbox Code Playgroud)

当我尝试在我的控制器中使用此问题时,我得到一个未定义的方法错误

#./app/controllers/foo_controller.rb
class FooController < ApplicationController

  include Foo

  def show
    Foo.somethingfoo # undefined method 'somethingfoo' for Foo:Module
    render plain: "Ohh no, It doesnt even show me because of the error above me"
  end
end
Run Code Online (Sandbox Code Playgroud)

据我所知somethingfoo应该被召唤但事实并非如此.我也试过somethingfoo在一个included do ... end块中定义关注但是这也不起作用.


有什么我想念的吗?控制器可以不用这样的问题吗?

ruby ruby-on-rails separation-of-concerns web

7
推荐指数
1
解决办法
7464
查看次数

asp.net 5在多个项目中依赖注入

我有一个ASP.NET 5 dnxcore解决方案,其中包含一些项目来区分我的逻辑:

  • API
  • 核心(具有业务逻辑服务)
  • DAL(存储库接口)
  • 实体框架(存储库实现)

现在我使用DI在我的API控制器的构造函数中调用我的服务:

private readonly IMyService _myService;
public Controller(IMyService myservice){ _myService = myService; }
Run Code Online (Sandbox Code Playgroud)

我核心中的服务也通过构造函数注入获取存储库:

private readonly IMyRepository _myRepo;
public MyService(IMyRepository myRepo){ _myRepo = myRepo; }
Run Code Online (Sandbox Code Playgroud)

目前我需要在我的API的启动类中定义我的DI容器以使其工作.

我的问题是,如何在我的Core-project中将存储库的DI容器的"构建"放入我的服务中.这样,我的API与我的服务使用Entity Framework这一事实松散耦合,因此我可以更改为mongodb,而无需更改我的API项目.

dependency-injection separation-of-concerns autofac repository-pattern asp.net-core

7
推荐指数
2
解决办法
2136
查看次数

分离业务逻辑和模型

我有这个问题一直困扰着我一段时间.乍一看,它似乎是一个相当基本的问题,但似乎没有一个明确的答案.我提出这个问题的基础是一个通过SQLAlchemy使用PostgreSQL的Python项目,但使用的特定语言和工具并不重要.

基本问题是在使用ORM时放置逻辑?更具体地说,我的映射类的方法应该采用什么逻辑?

似乎有一些明确的案例,例如,属性的基本验证,例如最小长度或某些电子邮件地址是否属于ORM层(甚至是数据库本身).

一个简单的具体示例是有序的,因此我们假设我们正在存储用户对象,用户有一个电子邮件地址(这是他们唯一的ID),一个密码和一个激活ID.创建帐户时,会分配激活ID并将其邮寄给用户,然后使用该ID设置密码.

我们来看几个场景:

  • 用户创建一个帐户;
  • 用户激活帐户(即设置密码).

因此,当用户创建帐户时,我们需要运行一些基本验证:

  • 电子邮件地址正确=> ORM;
  • 电子邮件地址unique => ORM或数据库(唯一约束);
  • 设置随机激活id => ORM

当用户激活她的帐户时,我遇到了问题.我想验证提供的密码(例如足够长?足够的数字?),但模型应使用某种散列或加密算法存储密码.似乎有两种选择:

1:检查模型之外的激活ID和密码有效性,散列密码然后将User.password设置为散列,并将User.activation id设置为null(以指示活动帐户).

2:创建一个User.activate(activation_id,password)方法,该方法验证每个并相应地设置User.password和User.activation_id属性.

3:混合选项,执行选项1,但在设置密码时设置某种挂钩或事件激活_id = null(如果我们假设可以设置激活ID或密码,则此挂钩满足基本一致性属性该模型).

我在互联网上搜索过,有些消息来源谈论这个问题(包括一些SO问题),但没有人真正回答这个问题.

python orm sqlalchemy separation-of-concerns

6
推荐指数
0
解决办法
1419
查看次数

在ActiveSupport :: Concern中访问包含类的受保护常量

在ActiveSupport :: Concern上下文中访问包含类的受保护常量的最简单方法是什么?

示例类:

module Printable
    extend ActiveSupport::Concern

private
    def print_constant
        puts MY_CONSTANT
    end
end

class Printer
    include Printable

    def print
        print_constant
    end

private
    MY_CONSTANT = 'Hello'.freeze
end
Run Code Online (Sandbox Code Playgroud)

此解决方案会产生错误:

NameError: uninitialized constant Printable::MY_CONSTANT
Run Code Online (Sandbox Code Playgroud)

我知道一种似乎有效的替代方案:

puts self.class::MY_CONSTANT
Run Code Online (Sandbox Code Playgroud)

但是,感觉不对.:-)

有更好的建议吗?

ruby model ruby-on-rails separation-of-concerns

6
推荐指数
2
解决办法
2451
查看次数