前言:本节是java伪代码

本章和第2章事务脚本示例相同,可以参考第2章。

在本章示例中,与第2章事务脚本最大的不同在于,每个类都有行为和数据。即使最简单的收入确认类也有一个简单的方法。

我们就从最简单的收入确认类RevenueRecognition开始:

class RevenueRecognition {
    ...
    成员变量略;
    public RevenueRecognition(Money amount, MfDate date) {
        this.amount = amount;
        this.date = date;
    }
    boolean isRecognizableBy(MfDate asOf){
        return asOf.after(date) || asOf.equals(date);
    }
}

合同类 在 计算特定日期前已确认的收入额方法 时 涉及 合同类收入确认类

class Contract {
    ...
    //成员变量、构造方法 见后文
    private List revenueRecognitions = new ArrayList();
    public Money recognizedRevenue(MfDate asOf) {
        Money result = Money.dollars(0);
        Iterator it = revenueRecognitions.itor();
        while(it.hasNext()){
            RevenueRecognition r= (RevenueRecognition)it.next();
            if (r.isRecognizableBy(asOf)) 
               result = result.add(r.getAmount)
        }
        return result;
    }
}

讨论:对于一些没有长远规划的 低端py人士 而言,领域模型模式缺点之一是,如果要完成一个特别简单的任务,仍然会强制你多各类相互交互。这就是被一些 低端py程序员 抱怨的原因。在那些 低端py程序员 阅读java的面向对象代码时,它们得花许多时间在一个个类之间跳跃,低端py程序员 由于没有经过系统的设计模式的训练和学习,难以找出各个类之间的关联关系。当时,这一抱怨有着丰厚的回报。当在给定日期前是否有金额可被确认的判断变得复杂,或者其他对象需要知道时,价值就体现了出来。将行为封装在相关对象中避免了冗余代码,而且也减弱了不同对象之间的耦合。
补全上文出现的 合同类 的构造方法(篇幅所限,成员变量略),其中需要 产品类。

Class Contract {
    ...
    成员变量略;
    public Contract(Product product,Money revenue,MfDate whenSigned) {
        this.product = product;
        this.revenue = revenue;
        this.whenSigned = whenSigned;
    }
}

对于产品类,由于我们要把这个产品类作为简单工厂类来生成各种具体产品,因此我们最好把构造方法设置为private,外部无法访问该构造函数,避免程序员无意中直接实例化产品类,失去了我们设计简单工厂类的良苦用心。然后,直接通过简单工厂类staitc 静态方法,具体策略类(本例使用了策略模式,其中装载具体算法的类,称为策略类)实例关联了的产品类实例

说明:简单工厂类,虽然我认为他起到解耦逻辑的作用,应该算是通用设计模式。但是业界大佬们认为他属于人类本能,不能算进设计模式范畴。另外,工厂方法模式抽象工厂模式,属于设计模式。

Class Product {
    ...
    成员变量略;
    private Product(String name ,RecognitionStrategy recognitionStrategy){
        this.name = name;
        this.recognitionStrategy = recognitionStrategy;
    }
	public static Product newWord(String name) {
	    return new Product(name, new CompleteRecognitionStrategy());
	}
	public static Product newExcel(String name) {
	    return new Product(name, new ThreeWayRecognitionStrategy());
	}
	public static Product newDBProcessor(String name) {
	    return new Product(name, new ThreeWayRecognitionStrategy());
	}
}

计算结果 创建收入确认对象 的过程进一步体现了大量运用细粒度对象的思想。在本例中,计算和创建始于顾客,然后通过产品类传递给策略类层次。我们在这里,将会使用通用设计模式策略模式(strategy pattern)。这个个著名的设计模式,允许将一组操作组合在一个小的类层次结构中。每个产品类的实例与策略类的实例相关联,这一策略实例决定了使用哪一个算法来计算收入确认额。

在本例中,我们有两个确认策略类的子类,分别对应两种不同的情况。

//抽象策略类
Class RecognitionStrategy {
	abstract void calculateRevenueRecognitions(Contract contract);
}
//
// 具体的策略类,一次性付款
Class CompleteRecognitionStrategy {
	void calculateRevenueRecognitions(Contract contract){
		contract.addRevenueRecognition(new RevenueRecognition, contract.getWhenSigned());
	}
}
// 这里是另外一种策略算法类,鉴于篇幅我们省略。本文主要是讲解设计模式,而不是业务逻辑。因此省略
Class ThreeWayRecognitionStrategy {
	void calculateRevenueRecognitions(Contract contract){
		...
		contract.addRevenueRecognition(.......);
	}
}

策略类的巨大价值在于提供了一些良好封装的插入点,来进行程序扩展。增加新的收入确认算法只需要创建一个新的策略类子类,并覆盖抽象方法。

每当我们创建产品的时候,就将他们与对应的策略对象上关联。具体方法见产品类的简单工厂方法。一旦所有对象构建完成,计算确定额就不必再了解策略子类的细节。

我们刚才把策略模式中的策略类完成了,最后,我们一定要在产品类中的计算确定额方法中,间接调用前面关联起来的策略类的算法,这样才能算是完成整个策略模式的布局。因此需要在 产品类 中加入方法,注意我故意把该方法的作用域设置为默认(就是什么也不写),因为我打算在后文把这个方法对合同类开发,今后后客户级别的调用者只能在合同类调用该方法:

void calculateRevenueRecognitions() {

    recognitionStrategy.calculateRevenueRecognition(contract);

}

此外,我们可以把 计算确定收入方法 整合进 合同类,操作如下所示,在合同类中加入成员方法,并且要把该成员方法设置为public,今后使用计算确认方法 的入口类就是 合同类:

public void calculateRevenueRecognitions(Contract contract) {
    recognitionStrategy.calculateRevenueRecognition(this);
}

 

以下是测试代码:

Product a = Product.newWord("钻石牌字处理程序");

Product b = Product.newExcel("啄木鸟数据处理程序");

Product c = Product.newDB("金拱门关系数据库系统");

Contract contract1 = new Contract(a , 价格,日期);

Contract contract2 = new Contract(a , 价格,日期);

Contract contract3= new Contract(a , 价格,日期);

contract1.calculateRevenueRecognitions();

contract2.calculateRevenueRecognitions();

contract3.calculateRevenueRecognitions();

本章总结:

本章主要讲的是企业设计模式中的领域模型模式,其中引入了一些策略模式,但我们重点是领域模型,所以不去继续深入讨论策略模式了。

领域模型相比于第一章的策略脚本而言,优势在于前者是面向对象的,可以利用其它通用设计模式,写出优秀的可维护的低耦合的代码;而后者只能是 低端py程序员 面向过程式的开发,造成大量冗余不可维护的辣鸡代码

在面向对象中,通过一个对象到另一个对象的连续传递可以把行为传给最有资格处理的对象。例如本例中,我把 calculateRevenueRecognitions 方法 从 策略类->产品类->合同类。合同类 作为最近的面向使用用户的一层,最有资格拥有使用calculateRevenueRecognitions方法。

此外还要注意,面向对象同时消除了许多条件判断行为。请注意在领域逻辑里没有任何条件判断子句。这是因为我们用领域模型,领域模型是三大领域逻辑中最面向对象的模型,面向对象的模型才可以使用设计模式,我们用到了策略设计模式。因为当你把决策实例和产品实例关联起来后,就确定了一条算法路径。当相应的关联了具体策略实例的产品类被实例化时,就相当于给你设置好了决策路径。当你的领域逻辑中有一组相似的条件判断语句时,领域模型可以很好的工作,因为相似的条件判断语句可以很好的转成成对象结构逻辑模型把复杂度从过程式的算法代码迁移到了对象间的关系中。逻辑越相似,代码越复杂,你就会发现系统不同部分所使用的相同关联就越多。