文章内容参考《Head First设计模式》及博客:https://www.cnblogs.com/yssjun/p/11102162.html
我们在前面的博客《设计模式入门》中提到要针对接口编程而不针对具体编程,然而当我们使用new时难道不是针对具体编程吗?
1、简单工厂:
- 定义:由一个工厂对象决定创建出哪一种产品类的实例
- 类型:创建性,但不属于GOF23种设计模式
-
适用场景
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心
- 优点:只需要传入一个正确的参数,就可以获取你所需要的对象而无需知道其创建细节。
- 缺点:工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则。
PhoneFactory类:手机代工厂(Factory) 【我们可以很容易的看到简单工厂其实就是把创建对象的职责封装起来了,从而达到了复用的效果,其他类可能也可以使用这个类来创建对象,所以简单工厂不算23种设计模式中的一种。
public class PhoneFactory {
public Phone makePhone(String phoneType) {
if(phoneType.equalsIgnoreCase("MiPhone")){
return new MiPhone();
}
else if(phoneType.equalsIgnoreCase("iPhone")) {
return new IPhone();
}
return null;
}
}
Phone类:手机标准规范类(AbstractProduct)
public interface Phone {
void make();
}
MiPhone类:制造小米手机(Product1)
public class MiPhone implements Phone {
public MiPhone() {
this.make();
}
@Override
public void make() {
// TODO Auto-generated method stub
System.out.println("make xiaomi phone!");
}
}
IPhone类:制造苹果手机(Product2)
public class IPhone implements Phone {
public IPhone() {
this.make();
}
@Override
public void make() {
// TODO Auto-generated method stub
System.out.println("make iphone!");
}
}
测试:
public class Demo {
public static void main(String[] arg) {
PhoneFactory factory = new PhoneFactory();
Phone miPhone = factory.makePhone("MiPhone"); // make xiaomi phone!
IPhone iPhone = (IPhone)factory.makePhone("iPhone"); // make iphone!
}
}
2、工厂方法:
- 定义:定义一个创建对象的工厂接口,但让实现这个接口的具体工厂类决定实例化哪个类对象,然后以这个类对象的父对象的形式返回该对象,工厂方法让类的实例化推迟到子类中进行。
- 类型:创建型
-
适用场景:
- 创建对象需要大量重复的代码
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
- 一个类通过其子类来指定创建哪个对象。
-
优点:
- 用户只需要关心所需产品对应的工厂,无需关心创建的细节。
- 加入新产品符合开闭原则,提高可扩展性。
-
缺点:
- 类的个数容易过多,增加复杂度。
- 增加了系统的抽象性和理解难度。
也就是定义一个抽象工厂,其定义了产品的生产接口,但不负责具体的产品,将生产任务交给不同的派生类工厂。这样不用通过指定类型来创建对象了。
接下来继续使用生产手机的例子来讲解该模式。
其中和产品相关的Phone类、MiPhone类和IPhone类的定义不变。
AbstractFactory类:生产不同产品的工厂的抽象类
public interface AbstractFactory { Phone makePhone(); }
XiaoMiFactory类:生产小米手机的工厂(ConcreteFactory1)
public class XiaoMiFactory implements AbstractFactory{ @Override public Phone makePhone() { return new MiPhone(); } }
AppleFactory类:生产苹果手机的工厂(ConcreteFactory2)
public class AppleFactory implements AbstractFactory { @Override public Phone makePhone() { return new IPhone(); } }
测试:
public class Demo { public static void main(String[] arg) { AbstractFactory miFactory = new XiaoMiFactory(); AbstractFactory appleFactory = new AppleFactory(); miFactory.makePhone(); // make xiaomi phone! appleFactory.makePhone(); // make iphone! } }
3、 抽象工厂模式
上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品Phone(AbstractProduct),如果要生成另一种产品PC,应该怎么表示呢?
最简单的方式是把2中介绍的工厂方法模式完全复制一份,不过这次生产的是PC。但同时也就意味着我们要完全复制和修改Phone生产管理的所有代码,显然这是一个笨办法,并不利于扩展和维护。
抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。
其UML类图如下:
从上面类图结构中可以清楚的看到如何在工厂方法模式中通过增加新产品接口来实现产品的增加的。
接下来我们继续通过小米和苹果产品生产的例子来解释该模式。
为了弄清楚上面的结构,我们使用具体的产品和工厂来表示上面的UML类图,能更加清晰的看出模式是如何演变的:
PC类:定义PC产品的接口(AbstractPC)
public interface PC {
void make();
}
MiPC类:定义小米电脑产品(MIPC)
public class MiPC implements PC {
public MiPC() {
this.make();
}
@Override
public void make() {
// TODO Auto-generated method stub
System.out.println("make xiaomi PC!");
}
}
MAC类:定义苹果电脑产品(MAC)
public class MAC implements PC {
public MAC() {
this.make();
}
@Override
public void make() {
// TODO Auto-generated method stub
System.out.println("make MAC!");
}
}
下面需要修改工厂相关的类的定义:
AbstractFactory类:增加PC产品制造接口
public interface AbstractFactory {
Phone makePhone();
PC makePC();
}
XiaoMiFactory类:增加小米PC的制造(ConcreteFactory1)
public class XiaoMiFactory implements AbstractFactory{
@Override
public Phone makePhone() {
return new MiPhone();
}
@Override
public PC makePC() {
return new MiPC();
}
}
AppleFactory类:增加苹果PC的制造(ConcreteFactory2)
public class AppleFactory implements AbstractFactory {
@Override
public Phone makePhone() {
return new IPhone();
}
@Override
public PC makePC() {
return new MAC();
}
}
测试:
public class Demo {
public static void main(String[] arg) {
AbstractFactory miFactory = new XiaoMiFactory();
AbstractFactory appleFactory = new AppleFactory();
miFactory.makePhone(); // make xiaomi phone!
miFactory.makePC(); // make xiaomi PC!
appleFactory.makePhone(); // make iphone!
appleFactory.makePC(); // make MAC!
}
}