大话设计模式(八)抽象工厂模式进化

来源:互联网 发布:软件开发环境 编辑:程序博客网 时间:2024/04/26 00:00

大话设计模式(八)抽象工厂模式进化

前情回顾

  在博文《大话设计模式(七)抽象工厂模式》中,我们了解了抽象工厂设计模式。在讲解反射机制时,我们提到反射机制实现了程序由编译时到运行时变量的指定。我们的设计不能防止需求的更改,那么我们的理想就是让变动变得最小。结合前面的代码讲解,当我们需要增加产品C时,那么我们就需要增加3个类。并修改3个类。

//抽象产品C,定义了产品的公共方法,产品A、B和C属于一个产品族  interface ProductC {    public void method1();    public void method2();}// 等级为1的具体产品Cclass ConcreateProductC1 implements ProductC {    @Override    public void method1() {        System.out.println("等级为1的产品C的method1()");    }    @Override    public void method2() {        System.out.println("等级为1的产品C的method2()");    }}// 等级为2的具体产品Cclass ConcreateProductC2 implements ProductC {    @Override    public void method1() {        System.out.println("等级为2的产品C的method1()");    }    @Override    public void method2() {        System.out.println("等级为2的产品C的method2()");    }}// 修改//抽象工厂,定义了生产族产品的方法;  interface AbstractFactory_ {      public ProductA factoryA();      public ProductB factoryB();  public ProductC factoryC(); }// 具体工厂(生产等级为1的族产品)class ConcreateFactory1 implements AbstractFactory_ {    // 生产等级为1的产品A    @Override    public ProductA factoryA() {        return new ConcreateProductA1();    }    // 生产等级为1的产品B    @Override    public ProductB factoryB() {        return new ConcreateProductB1();    }    // 生产等级为1的产品C    @Override    public ProductC factoryC() {        return new ConcreateProductC1();    }} //具体工厂(生产等级为2的族产品)class ConcreateFactory2 implements AbstractFactory_ {    // 生产等级为2的产品A    @Override    public ProductA factoryA() {        return new ConcreateProductA2();    }    // 生产等级为2的产品B    @Override    public ProductB factoryB() {        return new ConcreateProductB2();    }    // 生产等级为2的产品C    @Override    public ProductC factoryC() {        return new ConcreateProductC2();    }} 

优化之简单工厂模式

  可见,对于程序的扩展性、灵活性提出了严峻的挑战。为此,我们可以使用简单工厂模式来进行重新设计。

package cn.edu.ujn.designpattern;class ProductAccess{//  private static String name = "A1";     private static String name = "A2"; //  private static String name = "B1";//  private static String name = "B2"; //  private static String name = "C";    public static AbstractFactory_ creatProduct(){        AbstractFactory_ result = null;        switch (name) {            case "A1":                result = new ConcreateFactory1();                ProductA productA1 = new ConcreateProductA1();                productA1.method1();                break;            case "A2":                result = new ConcreateFactory1();                ProductA productA2 = new ConcreateProductA2();                productA2.method2();                break;            case "B1":                ProductB productB1 = new ConcreateProductB1();                productB1.method1();                break;            case "B2":                ProductB productB2 = new ConcreateProductB2();                productB2.method2();                break;/*          case "C1":                ProductC productC1 = new ConcreateProductC1();                productC1.method1();                break;  */              }        return result;    }}public class AbstractFactory_Modified {    public static void main(String[] args) {        ProductAccess.creatProduct();    }}

  我们通过利用简单工厂模式,抛弃了抽象工厂AbstractFactory_、抽象角色ProductA、ProductB、ProductC等若干个工厂类,取而代之的是ProductAccess类,由于事先设置了name的值(A1、A2、B1、B2、C1、C2),所以简单工厂的方法都不需要输入参数,这样在客户端就只需要ProductAccess.creatProduct();来生成具体的产品实例,客户端没有出现任何一个A1、A2、B1、B2、C1、C2的字样,达到了解耦的目的。

优化之反射机制

  但是,问题依旧存在。如果我们需要增加产品D获取,这样就需要在ProductAccess类中增加case了,同单例模式存在一样的问题:违反了OCP原则。为此,我们可以通过使用反射+单例模式实现。

package cn.edu.ujn.designpattern;class Fruit_Factory {    /**     * 获取实例     * @param productName 实体     * @return     */    public static Fruit createAnimal(String fullName){        try {            // 通过反射获取实例,通过给定类的字符串名称获取该类,类的全名            Class clazz = Class.forName(fullName);            try {                return (Fruit) clazz.newInstance();            } catch (InstantiationException e) {                throw new RuntimeException("实例化异常!",e);            } catch (IllegalAccessException e) {                throw new RuntimeException(e);            }        } catch (ClassNotFoundException e) {            throw new RuntimeException("这个实体类不存在!",e);        }    }}public class SimpleFactory_Reflection {    public static void main(String[] args) {         //测试        String className = "cn.edu.ujn.designpattern.Apple";         Fruit apple = (Fruit) Fruit_Factory.createAnimal(className);                apple.grow();    }}

优化之配置文件+反射

  这么写的话还是有点缺憾,因为在更换生成对象的时候,还是需要去改程序(改这个className的值)重编译,如果可以不改程序,那才是真正的符合OCP。为此,我们可以利用配置文件来解决更改的问题。

package cn.edu.ujn.designpattern;import java.io.IOException;import java.io.InputStream;import java.util.Properties;class Fruit_Factory {    /**     * 获取实例     * @param productName 实体     * @return     */    public static Fruit createFruit(){          Properties pro = new Properties();          InputStream ins;          ins = Fruit.class.getResourceAsStream("factory.properties");          try {              pro.load(ins);          } catch (IOException e) {              e.printStackTrace();          } finally{              try {                ins.close();            } catch (IOException e) {                e.printStackTrace();            }          }          String implClassStr = pro.get("implClass").toString();        try {            // 通过反射获取实例,通过给定类的字符串名称获取该类,类的全名            Class clazz = Class.forName(implClassStr);            try {                return (Fruit) clazz.newInstance();            } catch (InstantiationException e) {                throw new RuntimeException("实例化异常!",e);            } catch (IllegalAccessException e) {                throw new RuntimeException(e);            }        } catch (ClassNotFoundException e) {            throw new RuntimeException("这个实体类不存在!",e);        }    }}public class SimpleFactory_Reflection {    public static void main(String[] args) {         //测试        String className = "cn.edu.ujn.designpattern.Apple";         Fruit apple = (Fruit) Fruit_Factory.createFruit();        apple.grow();    }}

  可添加一个配置文件factory.properties,内容如下:

implClass=cn.edu.ujn.designpattern.Apple

  从这个角度上看,所有在使用简单工厂的地方,都可以考虑使用反射技术去除switch或if,解除分支判断带来的耦合,使之更加容易维护和扩展。

这里写图片描述
这里写图片描述
这里写图片描述

1 0