1 引子
上篇讲到,为了实现类的“开闭原则”和“单一职责原则”,把简单工厂模式改为工厂方法模式。通过工厂方法模式,客户只需要从对应的工厂拿到想要的衣服,从短袖工厂拿到短袖,毛衣工厂拿到毛衣,衬衣工厂拿到衬衣;但是,我们除了上衣外,还需要裤子;在这里客户需要按照不同的季节来拿衣服(包括上衣和裤子)。面向对象的抽象过程就是:①抽象工厂接口IFactory,可以生产上衣和裤子;②实体工厂类SpringFactory/SummerFactory/WinterFactory,这里按照季节来分工厂类别,每个季节的工厂生产对应季节的上衣和裤子,SpringFactory生产衬衣Shirt类和长裤Trousers类,SummerFactory生产短袖Cotta类和短裤Shorts类,WinterFactory生产毛衣Sweater类和棉裤Padd类;③抽象上衣类Clothes,抽象裤子类Pants;④实体衣服类,包括短袖Cotta,短裤Shorts,衬衣Shirt,长裤Trousers,毛衣Sweater,棉裤Padd类等;⑤客户端Client类。
① 抽象工厂IFactory:
public interface IFactory {
Clothes makeClothes(int num); // 生产上衣
Pants makePants(int num); // 生产裤子
}
② 实体工厂类:
SpringFactory:
public class SpringFactory implements IFactory {
@Override
public Clothes makeClothes(int num) {
return new Shirt(num); // 生产衬衣
}
@Override
public Pants makePants(int num) {
return new Trousers(num); // 生产长裤
}
}
SummerFactory:
public class SummerFactory implements IFactory {
@Override
public Clothes makeClothes(int num) {
return new Cotta(num); // 生产短袖
}
@Override
public Pants makePants(int num) {
return new Shorts(num); // 生产短裤
}
}
WinterFactory:
public class WinterFactory implements IFactory {
@Override
public Clothes makeClothes(int num) {
return new Sweater(num); // 生产毛衣
}
@Override
public Pants makePants(int num) {
return new Padd(num); // 生产棉裤
}
}
③ 抽象上衣类Clothes
public abstract class Clothes {}
抽象裤子类Pants
public abstract class Pants {}
④ 实体衣服类
衬衣类Shirt:
public class Shirt extends Clothes {
public Shirt(int num){
System.out.println("通过spring工厂制作"+ num +"件衬衫");
}
}
短袖类Cotta:
public class Cotta extends Clothes {
public Cotta(int num){
System.out.println("通过summer工厂制作"+ num +"件短袖");
}
}
毛衣类Sweater:
public class Sweater extends Clothes {
public Sweater(int num){
System.out.println("通过winter工厂制作"+ num +"件毛衣");
}
}
长裤类Trousers:
public class Trousers extends Pants {
public Trousers(int num){
System.out.println("通过spring工厂制作"+ num +"件长裤");
}
}
短裤类Shorts:
public class Shorts extends Pants {
public Shorts(int num){
System.out.println("通过summer工厂制作"+ num +"件短裤");
}
}
棉裤类Padd:
public class Padd extends Pants {
public Padd(int num){
System.out.println("通过winter工厂制作"+ num +"件棉裤");
}
}
⑤ 客户端类
public class Client {
public static void main(String[] args) {
IFactory springFactory = new SpringFactory();
springFactory.makeClothes(2);
springFactory.makePants(2);
System.out.println("=========================");
IFactory summerFactory = new SummerFactory();
summerFactory.makeClothes(3);
summerFactory.makePants(3);
System.out.println("=========================");
IFactory winterFactory = new WinterFactory();
winterFactory.makeClothes(4);
winterFactory.makePants(4);
}
}
运算结果:
通过spring工厂制作2件衬衫
通过spring工厂制作2件长裤
=========================
通过summer工厂制作3件短袖
通过summer工厂制作3件短裤
=========================
通过winter工厂制作4件毛衣
通过winter工厂制作4件棉裤
因为是通过抽象接口工厂实现不同的工厂,从而得到不同工厂生产不同的衣服,这种结构称为抽象工厂模式。
2 抽象工厂模式原理
《大话设计模式》中这样定义抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。我们再来看看工厂方法的定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到其子类;对比两个概念,可知抽象工厂的核心在于创建多个相关的对象,而工厂方法在于创建一个对象;所以抽象工厂是工厂方法的进阶版。
3 抽象工厂模式特点
抽象工厂模式的优点有哪些?
在客户端中依赖的是工厂的抽象接口,等到实际使用的时候就是具体的工厂对象,这符合类设计的“依赖倒置原则”,即面向接口编程。
当我们需要新增一个产品,比如鞋的时候,那么只需要给每个工厂造鞋的方法即可;当需要新增一个秋季工厂的时候,只需要继承抽象的工厂接口;客户端对于工厂的改变和产品的感知几乎为零,它只需要知道有这个工厂存在即可。抽象工厂同样符合“开闭原则”和“单一职责原则”。
抽象工厂模式有什么缺点呢?
虽然抽象工厂模式符合类的很多设计原则,但是也带有一定的复杂,新增加一个产品需要修改接口工厂,实体工厂类,还要直接新增产品类,一系列的操作显得很复杂,这个缺点也是伴随着“开闭原则”和“单一职责原则”来的。
4 抽象工厂模式适用场景
只有在合适的场景选择不同的设计模式。比如比较稳定且单个产品的场景可以选择简单工厂或者工厂方法模式,而对于实际比较复杂且易变动产品的场景可以选择抽象工厂模式。
5 参考资料
《大话设计模式》
http://www.runoob.com/design-pattern/abstract-factory-pattern.html