定义
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口。无须指定它们具体的类。
类型
创建型
适用场景
①、客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
②、强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。
③、提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体的实现。
优缺点
优点:
①、具体产品在应用层代码隔离,无须关心创建细节。
②、将一个系列的产品族统一到一起创建。
缺点:
①、规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
②、增加了系统的抽象性和理解难度。
产品等级结构和产品族
产品等级结构:Java视频、Python视频。
产品族:Java视频、Java书、Java文档。
代码实现
案例:假设一个键盘和一个显示器构成一台电脑。
产品等级结构:联想键盘和戴尔键盘;联想显示器和戴尔显示器。
产品族:联想键盘和联想显示器;戴尔键盘和戴尔显示器。
所以,这里需要先创建键盘和显示器的抽象类。
//显示器
public abstract class Display {
public abstract void produce();
}
//键盘
public abstract class KeyBoard {
public abstract void produce();
}
然后,创建具体的键盘和具体的显示器。
创建联想的键盘和联想的显示器。
public class LenovoDisplay extends Display{
@Override
public void produce() {
System.out.println("生产联想的显示器");
}
}
public class LenovoKeyBoard extends KeyBoard {
@Override
public void produce() {
System.out.println("生产联想的键盘");
}
}
创建戴尔的键盘和戴尔的显示器。
public class DellDisplay extends Display {
@Override
public void produce() {
System.out.println("生产戴尔的显示器");
}
}
public class DellKeyBoard extends KeyBoard {
@Override
public void produce() {
System.out.println("生产戴尔的键盘");
}
}
接着,需要创建一个生产电脑的工厂。
public interface ComputerFactory {
/**
* 获取显示器
*/
Display getDisplay();
/**
* 获取键盘
*/
KeyBoard getKeyBoard();
}
因为显示器加键盘构成一台电脑,所以需要声明产品族。
创建联想的产品族工厂。
public class LenovoComputerFactory implements ComputerFactory {
@Override
public Display getDisplay() {
return new LenovoDisplay();
}
@Override
public KeyBoard getKeyBoard() {
return new LenovoKeyBoard();
}
}
再创建戴尔的产品族工厂
public class DellComputerFactory implements ComputerFactory {
@Override
public Display getDisplay() {
return new DellDisplay();
}
@Override
public KeyBoard getKeyBoard() {
return new DellKeyBoard();
}
}
最后写一个测试类
@Test
public void test1(){
ComputerFactory factory = new DellComputerFactory();
Display display = factory.getDisplay();
KeyBoard keyBoard = factory.getKeyBoard();
display.produce();
keyBoard.produce();
}
测试结果:
C:\android\java\jdk1.8\bin\java.exe
生产戴尔显示器
生产戴尔键盘
这里创建了一个戴尔的产品族工厂,通过结果可知,从这个工厂里面获取的都是属于戴尔这个产品族的键盘和显示器。
相关源码
1. java.sql.Connection,MySQL获取的是MySQL的Statement和PreparedStatement
2. mybatis中的SqlSessionFactory
总结
①、应用层代码不和具体的产品发生依赖,它只和具体的产品族工厂发生依赖关系。
②、从具体的产品族工厂取出来的,肯定属于同一产品族。
③、扩展性好。只需要增加其他的产品族工厂和具体的产品就可以了。符合开闭原则。
④、如果产品族中扩展新的产品等级,这样接口和其实现都要发生改变,违背了开闭原则。
⑤、业务场景中,产品等级结构相对固定,并且还需要多个产品组合到一起来形成产品族的,不会频繁改动的,这样适合抽象工厂。
注意:
当一个工厂可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,这个时候选择抽象工厂就比工场方法更有效率。