在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
产品等级结构和产品族
产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机,乐视电视机,TCL电视机,则抽象电视机与具体品牌的电视机构成了产品等级结构,抽象电视机是父类,具体品牌的电视机是子类。
产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电视机,海尔电冰箱,海尔洗衣机。海尔电视机与海尔电冰箱、海尔洗衣机位于不同的产品等级结构中。
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。
抽象工厂模式
抽象工厂模式适用于需要生成产品族的情景。抽象产品类内部提供了多个其他抽象产品,抽象工厂类定义了产品的创建接口,通过具体的工厂子类,就可以生产相应的产品族对象,供用户端使用。
设计思想
抽象工厂(AbstractFactory):声明了一组用于创建一族产品的方法,每一个方法对应一个产品。
具体工厂(ConcreateFactory):实现了在抽象工厂中声明的创建产品的方法,这些产品构成了产品族。
抽象产品(AbstractProduct):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
具体产品(ConcreateProduct):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
在抽象工厂模式中,客户端不依赖产品类实例如何被创建、实现等细节,强调一系列相关的产品对象(属于同一产品族)一起创建对象。
伪代码
//抽象产品(手机)
public interface ITelephone{
public void call();
}
//具体产品(苹果手机)
public class AppleTelephone implements ITelephone{
public void call(){
System.out.println("这是苹果手机");
}
}
//具体产品(小米手机)
public class MiTelephone implements ITelephone{
public void call(){
System.out.println("这是小米手机");
}
}
//抽象产品(电脑)
public interface IComputer{
public void play();
}
//具体产品(苹果电脑)
public class AppleComputer implements IComputer{
public void play(){
System.out.println("这是苹果电脑");
}
}
//具体产品(小米电脑)
public class MiComputer implements IComputer{
public void play(){
System.out.println("这是小米电脑");
}
}
//抽象工厂
public interface IFactory{
public ITelephone createTelephone();
public IComputer createComputer();
}
//具体工厂(苹果工厂)
public class AppleFactory{
public ITelephone createTelephone(){
return new AppleTelephone();
}
public IComputer createComputer(){
return new AppleComputer();
}
}
//具体工厂(小米工厂)
public class MiFactory{
public ITelephone createTelephone(){
return new MiTelephone();
}
public IComputer createComputer(){
return new MiComputer();
}
}
//客户端
public class Client{
public static void main(String[] args){
IFactory miFactory = new MiFactory();
ITelephone miTelephone = miFactory.createTelephone();
IComputer miComputer = miFactory.createComputer();
IFactory appleFactory = new AppleFactory();
ITelephone appleTelephone = appleFactory.createTelephone();
IComputer appleComputer = appleFactory.createComputer();
}
}
优缺点
优点
1.当需要产品族时,抽象工厂可以保证客户端始终只使用同一个工厂的产品
2.抽象工厂增强了程序的可扩展性,对于新产品族的增加,只需要实现一个新的具体工厂即可,不需要对已有代码进行修改,符合开闭原则
缺点
1.产品族中扩展新的产品困难,需要修改抽象工厂的接口,不符合开闭原则
2.增加了系统的抽象性和复杂性
适用环境
在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
真实应用
javax.xml.parsers
包中的DocumentBuilderFactory用于创建DOM模式的解析器对象,DocumentBuilderFactory是一个抽象工厂类,无法直接实例化。但该类提供了一个newInstance()方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。
class XMLUtil {
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
public static Object getBean() {
try {
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));
//获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("className");
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c=Class.forName(cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
配置文件config.xml中存储了类名:
<?xml version="1.0"?>
<config>
<className>OperationAdapter</className>
</config>