抽象工厂模式是一种特殊的“工厂模式”
定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式,是工厂方法模式的升级版,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
抽象工厂模式包含了几个角色:
AbstractFactory:用于声明生成抽象产品的方法
ConcreteFactory:实现了抽象工厂声明的生成抽象产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中;
AbstractProduct:为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法;
Product:定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法。
通用类图如下:
其中 AbstractProductA 和 AbstractProductB 就是两个产品族的抽象类 (或者接口),而 Product1 和 Product2 就是产品族下的具体产品类,AbstractCreator 就是工厂的抽象。
我们可以用小米手机MIUI主题功能来举例,两套不同的主题都有共同类型的组件,如锁屏样式、通知栏、图标等。套用下抽象工厂的通用类图,我们不难发现,两个主题就相当于产品组抽象类AbstractProductA 和 AbstractProductB,而锁屏样式、通知栏、图标这些组件就是具体的产品类。
然后再来分析一下,如果有一个主题要在两个不同版本MIUI上运行,应该怎么设计?是编写两套程序运行于不同版本的MIUI上?这样实在是太浪费资源了,我们可以通过抽象工厂模式屏蔽掉MIUI版本对主题的影响。样式、通知栏、图标等都非常类似,唯一的不同是调用不同的工厂方法,由不同的产品类去处理与MIUI交互的信息,而这就是抽象工厂的优势。
代码编写
抽象工厂的通用类图我们已经了解了,下面就是具体代码的实现:
产品族的抽象类,Mouse(鼠标)和Keyboard(键盘),
public abstract class Mouse {
//每个产品相同的方法,不同的实现
public abstract void getMouseBrand();
}
public abstract class Keyboard {
//每个产品相同的方法,不同的实现
public abstract void getKeyboardBrand();
}
两个产品族的具体实现类代码,
public class LenovoMouse extends Mouse {
public void getMouseBrand() {
System.out.println("联想鼠标-Lenovo");
}
}
public class DellMouse extends Mouse {
public void getMouseBrand() {
System.out.println("-Dell-戴尔鼠标");
}
}
public class LenovoKeyboard extends Keyboard {
public void getKeyboardBrand() {
System.out.println("联想键盘-Lenovo");
}
}
public class DellKeyboard extends Keyboard {
public void getKeyboardBrand() {
System.out.println("-Dell-戴尔键盘");
}
}
抽象工厂类AbstractFactory,有N个产品族,在抽象工厂类中就应该有N个创建方法。我们这里定义两个产品族的产品创建,代码如下:
public abstract class AbstractFactory {
//创建键盘
public abstract Keyboard getKeybord();
//创建鼠标
public abstract Mouse getMouse() ;
}
然后是创建产品的具体工厂,有N个产品等级就应该有N个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务。
public class LenovoFactory extends AbstractFactory {
public Keyboard getKeybord() {
return new LenovoKeyboard();
}
public Mouse getMouse() {
return new LenovoMouse();
}
}
public class DellFactory extends AbstractFactory {
public Keyboard getKeybord() {
return new DellKeyboard();
}
public Mouse getMouse() {
return new DellMouse();
}
}
到此为止,我们把所有的角色都创建出来了,最后设计一个场景类,验证下是否能输出对应产品的信息,
public class AbstractTese {
public static void main(String[] args) {
//定义出两个工厂
AbstractFactory lenovoFactory = new LenovoFactory();
AbstractFactory dellFactory = new DellFactory();
//生产鼠标一
Mouse mouse1 = lenovoFactory.getMouse();
//生产鼠标二
Mouse mouse2 = dellFactory.getMouse();
//生产键盘一
Keyboard keyboard1 = lenovoFactory.getKeybord();
//生产键盘二
Keyboard keyboard2 = dellFactory.getKeybord();
//产品贴牌
mouse1.getMouseBrand();
mouse2.getMouseBrand();
keyboard1.getKeyboardBrand();
keyboard2.getKeyboardBrand();
}
}
运行结果:
联想鼠标-Lenovo
-Dell-戴尔鼠标
联想键盘-Lenovo
-Dell-戴尔键盘
总结
总结下抽象工厂模式的特点,抽象工厂是所有形式的工厂模式中最为抽象和最具一般性的一种形态,其优缺点大致如下:
1、隔离了具体类的生成,使得客户并不需要知道什么被创建,具有良好的封装性。
2、横向扩展容易。同个产品族如果需要增加多个 产品,只需要增加新的工厂类和产品类即可。
3、纵向扩展困难。如果增加新的产品组,抽象工厂类也要添加创建该产品组的对应方法,这样一来所有的具体工厂类都要做修改了,严重违背了开闭原则。