Oop 是马丁·福勒';s POEAA实施工作单元反模式?

Oop 是马丁·福勒';s POEAA实施工作单元反模式?,oop,orm,domain-driven-design,unit-of-work,domain-model,Oop,Orm,Domain Driven Design,Unit Of Work,Domain Model,马丁·福勒(Martin Fowler)在《POEAA》一书中介绍了工作单元的概念。如果您想拥有自动提交系统,它工作得非常好,在这个系统中,您的域模型使用工作单元将自己标记为新的、脏的、删除的或干净的。然后您只需要调用UnitofWork.commit(),模型的所有更改都将被保存。下面是具有此类方法的域模型类: public abstract class DomainModel{ protected void markNew(){ UnitOfWork.getCurr

马丁·福勒(Martin Fowler)在《POEAA》一书中介绍了工作单元的概念。如果您想拥有自动提交系统,它工作得非常好,在这个系统中,您的域模型使用工作单元将自己标记为新的、脏的、删除的或干净的。然后您只需要调用UnitofWork.commit(),模型的所有更改都将被保存。下面是具有此类方法的域模型类:

public abstract class DomainModel{

    protected void markNew(){
        UnitOfWork.getCurrent().registerNew(this);
    }

    protected void markDirty(){
        UnitOfWork.getCurrent().registerDirty(this);
    }

    protected void markRemoved(){
        UnitOfWork.getCurrent().registerRemoved(this);
    }        

    protected void markClean(){
        UnitOfWork.getCurrent().registerClean(this);
    }
} 
通过此实现,您可以通过业务逻辑方法将域模型标记为任何保存状态:

public class Message extends DomainModel{

    public void updateContent(User user, string content){
        // This method update message content if the the message posted time is not longer than 24 hrs, and the user has permission to update messate content.
        if(!canUpdateContent(user) && timeExpired()) throw new IllegalOperationException("An error occurred, cannot update content.");
        this.content = content;
        markDirty();
    }  
}
乍一看,它看起来很棒,因为您不必在存储库/数据映射器上手动调用insert、save和delete方法。然而,我发现这种方法存在两个问题:

  • 域模型与工作单元的紧密耦合:工作单元的这种实现将使域模型依赖于UnitOfWork类。UnitOfWork必须来自某个地方,静态类/方法的实现很糟糕。为了改进这一点,我们需要切换到依赖项注入,并将UnitOfWork的实例传递给域模型的构造函数。但这仍然将域模型与工作单元耦合在一起。理想情况下,域模型应仅接受其数据字段的参数(即,消息域模型的构造函数应仅接受与消息相关的内容,如标题、内容、发布日期等)。如果它需要接受UnitOfWork的参数,它将污染构造函数

  • 领域模型现在变得具有持久性意识:在现代应用程序设计中,特别是在DDD中,我们致力于持久性无知模型。域模型不应该关心它是否被持久化,它甚至不应该关心是否存在持久化层。通过在域模型上使用那些markNew()、markDirty()等方法,我们的域模型现在有责任通知应用程序的其余部分它需要持久化。虽然它不处理持久性逻辑,但模型仍然知道持久性层的存在。我不确定这是不是一个好主意,在我看来,这似乎违反了单一责任原则。还有一篇文章谈到了这一点:


  • 那你觉得呢?Martin Fowler中描述的原始工作单元模式是否违反了良好的OO设计原则?如果是这样,你认为它是反模式吗? 我不认为模型不应该依赖UoW。它更像是一个依赖于UoW的存储库,而存储库又依赖于模型

    如果您的存储库只依赖于抽象的UoW,那么了解持久化技术的唯一谜团就是具体的UoW

    我倾向于允许模型依赖的唯一类是模型的其他部分:域服务、工厂等。

    从DDD的角度来看,这是不应该做的事情。 DDD包含以下规则:

    应用程序服务在每个事务中只能修改一个聚合

    如果遵循此规则,则很清楚在应用程序服务操作期间更改了哪个聚合。然后,需要将此聚合传递到存储库以保存到数据库:

    repository.update(theAggregate);
    
    不需要其他电话。这会破坏您描述的模式的增益

    另一方面,您描述的模式引入了从域到持久性机制的依赖关系(取决于设计,要么是真正的依赖关系,要么只是概念上的依赖关系)现在,这是您应该避免的,因为它会大大增加模型的复杂性(不仅在内部,对客户也是如此)。

    因此,您不应该将此表单中的模式与DDD一起使用

    DDD之外 话虽如此,我认为这种模式是解决某个问题的众多解决方案之一。这个解决方案有优点和缺点,你在问题中描述了其中一些。在某些情况下,模式可能是最佳的权衡,因此


    不,这不是一种反模式。准确地说,没有“马丁·福勒的工作单元实施”一词。在这本书中,他区分了两种将修改对象注册到UoW的类型

    调用方注册其中只有调用对象知道UoW,并且必须将(被调用方)域对象标记为脏对象。据我所知,这里没有反模式或不良做法

    对象注册其中域对象向UoW注册自身。这里还有两个选项:

    要使此方案起作用,工作单元需要传递给 在一个著名的地方。通过工作单元 周围环境是乏味的,但在某些情况下通常没有问题 会话对象的类型

    代码示例使用的是
    UnitOfWork.GetCurrent()
    ,它更接近后一个选项,并且由于紧密耦合的隐式依赖关系(服务定位器样式),目前被广泛认为是一种反模式

    但是,如果选择了第一个选项,即将UoW传递给域对象,让我们假设一个工作单元抽象,这会是一种不好的做法吗?从依赖关系管理的角度来看,显然不是

    现在仍然是坚持无知方面。我们是否可以说,一个对象可以向另一个对象发出信号,表明它刚刚被编辑/创建/删除,具有持久性意识?非常有争议。 相比之下,如果我们看看最近的域对象实现,例如事件源中的域对象实现,我们可以看到聚合的思想或多或少是相同的。这是否违反了无知?我不这么认为

    底线:福勒选择的具体代码说明了许多UoW可能性中的一种,显然现在被认为是不好的做法,但关于问题,更是如此#1您指出了一个