从《 POEAA》一书中,马丁·福勒(Martin Fowler)介绍了“工作单元”的概念。如果您要使用自动提交系统,则该方法效果很好,在该系统中,您的域模型使用工作单元将其自身标记为新的,脏的,已删除的或干净的。然后,您只需要调用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的实例传递给Domain Model的构造函数。但这仍然将领域模型与工作单元结合在一起。同样理想地,领域模型应该只接受其数据字段的参数(即消息领域模型的构造函数应只接受与消息相关的内容,例如标题,内容,日期等)。如果它将需要接受UnitOfWork的参数,它将污染构造函数。
领域模型现在变得具有持久性意识:在现代应用程序设计中,尤其是DDD,我们致力于建立对持久性无知的模型。领域模型不应该关心是否持久化,甚至不关心是否存在持久层。通过在域模型上使用那些markNew(),markDirty()等方法,我们的域模型现在有责任通知我们的其余应用程序它需要持久化。尽管它不处理持久性逻辑,但是该模型仍然知道持久性层的存在。我不确定这是否是一个好主意,对我来说似乎违反了单一责任原则。还有一篇有关此的文章:
http://blog.sapiensworks.com/post/2014/06/04/Unit-Of-Work-is-the-new-Singleton.aspx/


所以你怎么看? Martin Fowler中描述的原始工作单元模式是否违反了良好的OO设计原则?如果是这样,您是否认为它是反模式?

最佳答案

完全准确地说,没有一个“马丁·福勒对工作单元的实施”。在书中,他区分了将修改对象注册到UoW的两种类型。

仅主叫对象知道UoW且必须将(被叫方)域对象标记为脏方的主叫方注册。据我所知,这里没有反模式或不良做法。

域对象向UoW进行自身注册的对象注册。同样,这里有两个选择:


为了使该计划生效,需要将工作单元传递给
物体或将物体放置在众所周知的地方。通过工作单元
周围很乏味,但通常不会出现在某些地方
会话对象的种类。


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

但是,如果选择了第一个选项,即将UoW传递到域对象,并假设一个工作单元抽象,这是不好的做法吗?从依赖性管理的角度来看,显然不是。

现在仍然是持久性无知方面。我们能否说一个可以通知另一个对象刚刚被编辑/创建/删除的对象,它具有持久性意识?值得商bat的。
相比之下,如果我们查看最近的领域对象实现,例如“事件源”中的实现,则可以看到聚集can be responsible for keeping a list of their own uncommitted changes大致相同的想法。这是否违反了持久性的愚昧?我不这么认为。

底线:Fowler选择用来说明许多UoW可能性的特定代码现在显然已经被认为是不好的作法,但是关于您指出的问题#1并不是真正的问题#2,更多的是这样。但这并没有取消他所写的其他实现的资格,也不是整个UoW模式的变化跟踪机制如今大部分时间都隐藏在第三方库的魔力(阅读:ORM)中,并且没有像本书示例中那样进行硬编码。

08-06 19:28