设计模式学习-抽象工厂模式
1.定义
提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类。
2.类图
3.代码示例
1 package com.zhaoyangwoo.abstractfactory; 2 3 /** 4 * Created by john on 16/5/2. 5 * @author wuzhaoyang 6 * <p> 7 * 抽象工厂:多个抽象产品类,派生出多个具体产品类;一个抽象工厂类,派生出多个具体工厂类;每个具体工厂类可创建多个具体产品类的实例。 8 * 即提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们的具体的类。“一对多”的关系。 9 * </p> 10 */ 11 public class AbstractFactory { 12 13 public static void main(String[] args) { 14 Factory factory1= new Factory1(); 15 ProductA productA1 = factory1.createProductA(); 16 ProductB productB1 = factory1.createProductB(); 17 productA1.getName(); 18 productB1.getBrand(); 19 20 Factory factory2= new Factory2(); 21 ProductA productA2 = factory2.createProductA(); 22 ProductB productB2 = factory2.createProductB(); 23 productA2.getName(); 24 productB2.getBrand(); 25 26 } 27 } 28 29 30 interface ProductA{ 31 void getName(); 32 } 33 34 interface ProductB{ 35 void getBrand(); 36 } 37 38 interface Factory{ 39 ProductA createProductA(); 40 ProductB createProductB(); 41 } 42 43 class ProductA1 implements ProductA{ 44 45 @Override 46 public void getName() { 47 System.out.println("i'm productA1"); 48 } 49 } 50 51 class ProductA2 implements ProductA{ 52 53 @Override 54 public void getName() { 55 System.out.println("i'm productA2"); 56 } 57 } 58 59 class ProductB1 implements ProductB{ 60 61 @Override 62 public void getBrand() { 63 System.out.println("i'm productB1"); 64 } 65 } 66 67 class ProductB2 implements ProductB{ 68 69 @Override 70 public void getBrand() { 71 System.out.println("i'm productB2"); 72 } 73 } 74 75 class Factory1 implements Factory{ 76 77 @Override 78 public ProductA createProductA() { 79 return new ProductA1(); 80 } 81 82 @Override 83 public ProductB createProductB() { 84 return new ProductB1(); 85 } 86 } 87 88 class Factory2 implements Factory{ 89 90 @Override 91 public ProductA createProductA() { 92 return new ProductA2(); 93 } 94 95 @Override 96 public ProductB createProductB() { 97 return new ProductB2(); 98 } 99 }
4.应用场景举例
- 创建复杂对象,隔离对象创建的具体过程
- 客户端不需要知道具体产品类的类名,只需要知道所对应的具体工厂即可,具体的产品对象由具体工厂类创建;
5.JDK源码中的模式实现
为响应《设计模式-工厂模式》的思考1,不打算区分工厂方法和抽象工厂的实现。但是为了更好的理解,我们看javax.xml.transform.TransformerFactory的源码实现。
抽象工厂角色:
1 package javax.xml.transform; 2 3 /** 4 * 我们看作者的注释明确写到,这个"abstractFactory"是用来创建Transformer和Templates两个产品族"product" 5 * 6 * 7 * <p>A TransformerFactory instance can be used to create 8 * {@link javax.xml.transform.Transformer} and 9 * {@link javax.xml.transform.Templates} objects.</p> 10 * 11 */ 12 public abstract class TransformerFactory { 13 14 /** 15 * Default constructor is protected on purpose. 16 */ 17 protected TransformerFactory() { } 18 19 20 ... 21 22 public abstract Transformer newTransformer(Source source) 23 throws TransformerConfigurationException; 24 25 26 27 public abstract Templates newTemplates(Source source) 28 throws TransformerConfigurationException; 29 30 ... 31 32 }
抽象产品角色:
1 //两个抽象产品,构成产品族 2 public abstract class Transformer { 3 4 /** 5 * Default constructor is protected on purpose. 6 */ 7 protected Transformer() { } 8 9 ... 10 } 11 12 public interface Templates { 13 14 ... 15 16 Transformer newTransformer() throws TransformerConfigurationException; 17 18 ... 19 }
具体工厂角色:
1 public class TransformerFactoryImpl 2 extends SAXTransformerFactory implements SourceLoader, ErrorListener 3 { 4 5 @Override 6 public Transformer newTransformer() 7 throws TransformerConfigurationException 8 { 9 TransformerImpl result = new TransformerImpl(new Properties(), 10 _indentNumber, this); 11 if (_uriResolver != null) { 12 result.setURIResolver(_uriResolver); 13 } 14 15 if (!_isNotSecureProcessing) { 16 result.setSecureProcessing(true); 17 } 18 return result; 19 } 20 21 @Override 22 public Templates newTemplates(Source source) 23 throws TransformerConfigurationException 24 { 25 // If the _useClasspath attribute is true, try to load the translet from 26 // the CLASSPATH and create a template object using the loaded 27 // translet. 28 if (_useClasspath) { 29 String transletName = getTransletBaseName(source); 30 31 if (_packageName != null) 32 transletName = _packageName + "." + transletName; 33 34 try { 35 final Class clazz = ObjectFactory.findProviderClass(transletName, true); 36 resetTransientAttributes(); 37 38 return new TemplatesImpl(new Class[]{clazz}, transletName, null, _indentNumber, this); 39 } 40 catch (ClassNotFoundException cnfe) { 41 ErrorMsg err = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, transletName); 42 throw new TransformerConfigurationException(err.toString()); 43 } 44 catch (Exception e) { 45 ErrorMsg err = new ErrorMsg( 46 new ErrorMsg(ErrorMsg.RUNTIME_ERROR_KEY) 47 + e.getMessage()); 48 throw new TransformerConfigurationException(err.toString()); 49 } 50 } 51 ... 52 53 return new TemplatesImpl(bytecodes, transletName, 54 xsltc.getOutputProperties(), _indentNumber, this); 55 } 56 57 58 }
具体产品角色:
1 public final class TransformerImpl extends Transformer 2 implements DOMCache, ErrorListener 3 { 4 ... 5 } 6 public final class TemplatesImpl implements Templates, Serializable { 7 ... 8 }
6.思考
- 抽象工厂最大的特点在哪里?
最明显的在于扩展产品等级(具体工厂)很容易,但扩展产品族(具体产品)很难。由本文的代码实现可以看出,如果我这个时候给工厂添加新任务,生产ProductC,那需要怎么做?首先我必须修改Factory类添加
createProductC():ProductC 方法,另外最麻烦的是所有实现Factory的工厂都必须修改实现该方法。但是如果我需要Factory3来生产另一质量等级的ProductA3和ProductB3,只需要添加一个Factory3实现即可。
javax.xml.xpath.XPathFactory和
javax.xml.parsers.DocumentBuilderFactory运用的是抽象工厂?
首先我还是要声明一点,不管你用的是抽象工厂也好还是工厂方式也罢,本质上都是一样的,通过工厂封装产品生产的具体过程,客户端只需给出需要的产品,无需关心生产过程。
其次抽象工厂和工厂方法唯一的区别就是是否构成产品族。
这两个类的产品族有点变异,我们拿javax.xml.xpath.XPathFactory
举例,它的产品族包含两个产品:
-
public static XPathFactory newInstance();
-
public abstract XPath newXPath();
-
其中一个产品不能是自己吗?有疑问的请移步《设计模式-工厂模式》的思考问题2
7.参考
2.设计模式:工厂方法模式(Factory Method)和抽象工厂模式(Abstact Factory)