【问题标题】:Designing Domain Model设计领域模型
【发布时间】:2013-03-23 17:00:13
【问题描述】:

根据域模型模式,我们必须对域实体也有行为。我正在使用实体框架进行数据访问。我已提取所有实体并作为部分类移至域层。现在我在域层中有另一组部分类,其行为与存储库通信。问题是存储库也引用域模型中的实体导致循环引用。

谁能为此提供设计解决方案?

【问题讨论】:

    标签: asp.net-mvc entity-framework domain-driven-design domain-model


    【解决方案1】:

    很难用抽象的术语来谈论,所以这里有一个例子可能会有所帮助。想象一下,我们有一项服务可以让Cars 去旅行。在此行程中,Cars 可能会没油,需要换油。

    class Car {
        private GasTank gasTank;
        private OilPan oilPan;
    
        double MPG = 25.0;
    
        void drive( int distance ) {
            gasTank.consume( distance / MPG );
            oilPan.dirty( distance / OilDirtyRate ); // Making up a term here...but Oil gets dirty
        }
    
        void fillUp() {
            gasTank.fillUp();
        }
    
        void changeOil() {
            oilPan.empty();
            oilPan.add( new Oil() );
        }
    }
    
    // These are value objects, there's no identity here
    class GasTank { }  // Imagine above methods defined
    class OilPan { } // more methods
    
    class CarRepository {
        Car findByVIN( String vin ) {
            // Search Car collection or database
            return car;
        }
        boolean register( Car car ) {
            carDao.insert( car.toDTO() );
        }
        boolean update( Car car ) {
            // write to persistence, etc.
        }
    }
    
    class TripService {
        private CarRepository carRepo;
    
        void takeTrip( String carVin, int milesToGo ) {
            Car car = carRepo.findByVIN( carVin );
            // calculate distance
            while ( milesToGo > 0 ) {
                car.drive( 200 );
                milesToGo -= 200;
                if ( car.isOutOfGas() ) {
                    car.fillUp();
                }
                if ( car.needsOilChange() ) {
                    car.changeOil();
                }
            }
            carRepo.update( car );
        }
    }
    

    我很抱歉使用了另一个汽车示例(以及 Java,因为您说的是 C#),但是您可以看到 Car 仍然具有逻辑,但是 TripService 可以将 Car 作为一个整体来操作。 Car 负责处理它的内部逻辑,例如消耗气体和弄脏油。如果油箱中没有足够的气体,drive 可能会返回实际覆盖的距离。如果不是正常发生,它可能会引发异常。 drive 方法还可以检查汽车是否启动、是否有油、是否有气、是否扣好座椅节拍。启动汽车可能会以不同的速度消耗汽油。您可以看到 TripService(“应用程序”)与CarRepository 对话并操纵Car,但Car 对CarRepository 一无所知,但仍然有逻辑。

    处理汽油和机油更换可能不是TripService 在现实生活中的职责,但在模拟汽车磨损的应用程序中,它可能会承担这些责任。

    回到抽象术语,您的服务与存储库和工厂交互以获取域对象。然后他们在需要的地方编排域对象之间的交互。毕竟,有些东西必须告诉您的域对象该做什么。这就是服务发挥作用的地方。域对象对存储库一无所知,因为它们不了解持久性。知道自己是如何持久化的不会影响业务逻辑,因此您无需在域对象中处理它。他们只处理业务逻辑和维护不变量。存储库必须了解域对象,因为它们会持久化和检索它们。

    【讨论】:

    • 所以。域模型中将有一组服务,它们将负责从存储库或域模型上方的层填充域实体
    • 是的,我认为这是准确的。我会澄清您的服务和存储库交互。该服务向存储库请求域对象。从存储库返回后,它基本上就可以在您的域层中使用了。
    【解决方案2】:

    将具有与存储库对话的行为的域层中的部分类移动到适当的服务中。

    您的模型不应该知道任何关于存储库的信息。您的存储库获取模型并将其保存到您的数据库中。

    然后,您在模型之上有一个层,无论是 ASP.NET MVC 中的 WCF 服务或控制器,还是位于顶部的控制台应用程序中的 Main 方法,它组织域模型交互,然后通过存储库持久保存到数据库.

    您的模型不是放置所有应用程序的地方。

    【讨论】:

    • 你的解决方案违背了领域模型模式martinfowler.com/eaaCatalog/domainModel.html的原则
    • 愿意解释一下您认为它与域模型模式有何冲突吗?因为我看不到有什么作用。
    • 如果我将行为类转移到服务中,我在域层中的实体将变得像 DTO。有关域模型模式的更多信息,请参阅我之前评论中的链接
    • 如果您的域类需要与您的存储库通信,那么它们就不是域类。 Martin Fowler 没有说过所有代码都必须进入域模型。您需要一些东西来控制与域模型的交互,然后保持更改。请参阅此处了解更多信息stackoverflow.com/questions/2268699/…
    • 我很想知道在没有来自某个存储库的数据的情况下,域模型会有哪些行为不足。可以说,如果我为数据公开一些基础设施服务并直接从应用程序服务中使用它们,我看不到引入领域层和领域驱动设计的真正优势
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多