弄清楚在什么场合下该使用怎样的设计模式才是最重要的
——谨记
1 简单工厂模式:
适用场合(个人理解):
我们有属于某一个类型的许多类(可能是实现同一接口的一些类,也可能是继承同一父类),只有在运行时才能确定出该实例化哪一个(或者说,你希望灵活的在运行中创建),这时候,我们就可以使用简单工厂模式。简单工厂模式,就是在运行期间根据情况,创建出相应的类的对象。
对应的uml图
图1.1 简单工厂uml图(注1)
解释: Product1、Product2、Product3是虚基类Product的子类(当然可以有更多子类),Client需要在运行时决定应该创建哪一个子类,这时,Client依靠SimpleFactory的createProduct(String product)方法来动态创建所需要的类。createProduct(Stringproduct)很好实现,如上图,只要使用if..else..语句就可以了。
为了节省资源,createProduct方法通常定义为静态方法,或者,将SimpleFactory写成单例模式。由于在子类中,静态方法是不可以被重载的,而单例模式由于构造函数是私有的,不能被继承(注2)。所以,如果增加了产品(也就是Product的子类),不得不修改createProduct方法,这违法了开闭原则,这也是简单工厂模式最大的弊病。
可以利用反射机制:return Class.forName(product).newInstance();※注1:Product也可以使=是一个接口,对应Product1、Product2、Product3实现这个接口。
※注2:单例模式的构造函数也可以定义为protected,在Java中必须注意防止同包内的其他类构造这个单例。但是即便如此,应用单例模式时,很少创建子类。
2 工厂模式:
有些网站、书中将工厂模式看做是简单工厂模式的升级版,我却怎么想也想不明白,因为我觉得,这两个模式完全是应用在不同的场景。
适用场合(个人理解):
工厂模式非常好的体现了依赖倒置原则,即A:高层模块不应该依赖于底层模块,都应该依赖抽象。B:抽象不应该依赖于细节,细节应该依赖于抽象。
假设:你在开发一个工程,采取的是自上而下的分析方法。你确定了两个上层的抽象类:Creator和Product,其关系为Creator需要创建并使用Product类。很显然Product是抽象类嘛,在Create中,你无法创建(注3)Product类。这时你就可以使用工厂模式来解决这个问题,uml图如下:
图2.1 工厂模式uml图(注4)
解释:这里面注意的就是Creator定义了一个抽象方法,而在其某一个成员方法anOperator就用到了这个方法。这样,Creator类就可以“创建”Product的对象了。而真正的创建方法,在其子类中实现。也就是我们看到很多书中说的,工厂模式把某一个类的实例化延迟到了子类。
工厂模式的好处,一则没有违法依赖倒置原则,减少了代码维护的压力。同时,Creator与Product建立了逻辑上的关联,也就是这两个类在抽象的层次上建立了关联。起到了代码复用的作用,减少了开发工作量。反过来看,在Creator类与Product存在这样的“创建并使用”的关系时,可以使用工厂模式。
※注3:也不要试图在Create中就创建Product的子类,这样违反依赖倒置原则,导致抽象的Create依赖于Product的具体子类。
※注4:根据情况,product自然也可以是接口,对应ConcreteProduct实现这个接口。
3 抽象工厂模式:
我不得不说,抽象工厂模式,稍微有些复杂。
适用场合(个人理解):
与工厂模式对比来说:
1. 有多个产品(Product),其实,工厂模式,也可以由多个产品。
2. 这些产品的子类(或者是实现接口的类)分成了两个或多个系列。
3. 我们希望在客户端中,使用同一个系列的产品。
这时候,我们就可以使用抽象工厂模式了。uml图如下:
图3.1 抽象工厂模式uml图
解释:
多个产品:AbstractProductA、AbstractProductB;
两个系列:系列1:ProductA1、ProductB1;
系列2:ProductA2、ProductB2;
与工厂模式类似,这里的AbstractFactory相当于上个UML图中的Creator,AbstractFactory 将产品对象的创建延迟到其ConcreteFactory。不同的是,每个具体的类创建一系列的产品。客户端(Client)使用一个特定的ConcreteFactory类,强制的使用了同一系列的产品。