设计模式 – 3:策略模式、工厂模式

策略模式和工厂模式主要用来应对软件开发过程中,由于需求的变化导致对象算法的变化以及需要创建的对象的具体类型经常变化。

例如我们要实现一个税务计算的程序,需要判断不同的国家来确定不同的税务计算方法。不难想到用这样的方法来设计:

这样的设计支持计算中国、美国和德国的税务。从设计模式的目的来考虑,假设我们新增这样一个需求变化——新增一个日本税务的计算方法。这个时候我们就要修改 TaxType 类型以及 calculate 函数。这样就破坏了「开闭原则」,导致这一块代码是不可复用的。

所谓「可复用」指的是编译单位上的「可复用」,即当代码编译成二进制文件并部署后,是不需要重新编译的。

考虑重新组织这些税务计算策略。我们可以定义一个抽象类 AbstractTax 来描述抽象的计算策略,然后用具体的类来表示具体的计算策略。

这就是「策略模式」:

定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。

这样就可以不用破坏开闭原则。那么新的问题又产生了,在使用这些类的时候,我们又会陷入条件判断的僵局,这必然又会打破开闭原则。这个时候我们就需要引入「工厂模式」,我们要为不同的国家创建不同的 AbstractTax 子类对象(具体的策略)。

定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。

这里我们可以让每一个具体的策略类对应一个工厂,这个工厂继承自工厂的抽象模型。

最后我们再把整个运行过程整合到 SalesOrder 类当中。

我们可以看出使用工厂模式解除了「编译时」 SalesOrder 对具体税务类型的依赖,提高了编译单元代码的「复用性」。

我们可以画出这个程序的依赖图(编译时依赖):

依赖图

其中 SalesOrderTaxFactory 是一条虚线,意味着在工厂模式中,我们常常也将工厂的抽象类的指针作为 SalesOrder 的属性,但是这里代码中没有体现出来。我们发现 SalesOrder 依赖于抽象的 AbstractTax 以及 TaxFactory,它们是稳定的,而具体的 TaxFactory 依赖于抽象的 AbstractTax 以及 TaxFactory,这里体现了OOP的「依赖倒置原则」,即 SalesOrder 应该依赖「稳定的」抽象,具体的实现也应该依赖于抽象。

下面是完整的代码,注意在工程当中应当一个类放在一个文件中,这样才能达到真正的「编译单元可复用」。

说点什么

avatar
  Subscribe  
提醒