美文网首页
设计模式 --工厂方法模式(FACTORY METHOD)

设计模式 --工厂方法模式(FACTORY METHOD)

作者: 小杰的快乐时光 | 来源:发表于2018-08-18 20:04 被阅读0次

    什么是工厂方法模式?
    定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
    工厂方法使一个类的实例化延迟到其子类。

    通用类图如下:


    工厂模式类图.png

    工厂方法模式通用代码:
    ①产品抽象类:负责定义产品共性

    public abstract class Product {
       //产品的公共方法
       public void method1(){
          //业务逻辑处理代码
       }
       //其他抽象方法
       public abstract void method2();
    }
    

    具体的产品实现类可以有多个,都继承于抽象产品类
    ②产品实现类

    public class ConcreteProduct1 extends Product {  //具体产品实现类1
       @Override
       public void method2() {
          //业务逻辑处理代码
       }
    }
    
    public class ConcreteProduct2 extends Product { //具体产品实现类2
       @Override
       public void method2() {
          //业务逻辑处理代码
       }
    }
    

    ③抽象工厂类:负责定义产品对象的产生

    public abstract class AbstractFactory {
       /**
        * 创建一个产品对象,其输入参数可以自行设置
        * 输入参数:通常为String,Enum,Class,也可以为空
        */
       public abstract <T extends Product>T createProduct(Class<T> c);
    }
    

    ④具体的工厂实现类:定义具体如何产生一个产品对象

    public class ConcreteFactory extends AbstractFactory {
       @Override
       public <T extends Product>T createProduct(Class<T> c) {
          Product product= null;
          try {
             product =(Product) Class.forName(c.getName()).newInstance();
          } catch (InstantiationException e) {
             e.printStackTrace();
          } catch (IllegalAccessException e) {
             e.printStackTrace();
          } catch (ClassNotFoundException e) {
             e.printStackTrace();
          }
          return (T)product;
       }
    }
    

    ⑤场景类:调用相关方法

    public class Client {
       public static void main(String[] args) {
          AbstractFactory factory = new ConcreteFactory();
          Product product = factory.createProduct(ConcretepProduct1.class);
       }
    }
    

    工厂方法模式的优点:
    ①良好的封装性,代码结构清晰
    ②优秀的扩展性
    ③屏蔽产品类,很强的灵活性
    ④解耦性强

    工厂方法模式的使用场景:
    ①工厂方法模式是new方法的替代品,在所有需要生成对象的地方都可以使用,但需要谨慎的考虑是否要增加一个工厂类进行管理,防止增加代码复杂度。
    ②需要灵活的,可扩展的框架时,可以考虑采用工厂方法模式。
    ③可以用在异构的项目中。
    ④可以在测试驱动开发的框架下使用。

    工厂方法模式的扩展
    ①缩小为简单工厂模式
    问题:一个模块仅需要一个工厂类,没必要把它生产出来,使用静态方法即可。
    解决思路:以上面代码为例,去掉AbstractFactory抽象类,同时将createProduct方法设置为静态类型,简化类的创建过程。
    那么ConcreteFactory代码修改如下:

    public class ConcreteFactory{
       public static <T extends Human> T createProduct(Class<T> c) {
          Product product= null;
          try {
             product = (Product) Class.forName(c.getName()).newInstance();
          } catch (InstantiationException e) {
             e.printStackTrace();
          } catch (IllegalAccessException e) {
             e.printStackTrace();
          } catch (ClassNotFoundException e) {
             e.printStackTrace();
          }
          return (T)product;
       }
    }
    

    客户端类修改如下:

    public class Client {
       public static void main(String[] args) {
          Product product =ConcreteFactory.createProduct(ConcretepProduct1.class);
       }
    }
    

    运行结果没有变化,但是调用者变简单了,该模式是工厂方法模式的简化版,所以称之为:简单工厂模式,也叫静态工厂模式。缺点是:扩展困难,不符合开闭原则。

    ②升级为多个工厂类
    问题:在一个复杂的项目中,将所有产品类放到一个工厂方法中进行初始化会使代码结构不清晰。
    解决思路:为每一个产品定义一个创造者,然后由调用者自己选择与哪个工厂方法关联。

    AbstractFactory抽象类代码修改如下:

    public abstract class AbstractFactory {
       public abstract Product createProduct();
    }
    

    抽象方法中已不需要传递参数,每个具体的工厂都已经非常明确各自的职责。

    public class Product1Factory extends AbstractFactory {
            public Product createProduct(){
                   return new ConcreteProduct1();
            }
    }
    
    public class Product2Factory extends AbstractFactory {
            public Product createProduct(){
                   return new ConcreteProduct2();
            }
    }
    

    客户端类修改如下:

    public class Client {
       public static void main(String[] args) {
         Product product1 = (new Product1Factory()).createProduct();
         Product product2 = (new Product2Factory()).createProduct();
       }
    }
    

    回顾一下:为每一个产品实现类都创建一个具体的工厂类,职责清晰,结构简单,缺点是:可扩展性与可维护性带来困难。

    ③替代单例模式
    单例模式的核心在于:内存中只能有一个对象,那么可以使用工厂方法模式也只创建一个对象么?答案是肯定的。
    首先创建一个Singleton类:

    public class Singleton {
       private Singleton(){}
       public void doSomething(){}
    }
    

    将构造方法私有化,这样就无法通过正常方式构造一个Singleton对象,那么SingletonFactory应该如何创建一个单例对象呢?答案是:通过反射。

    public class SingletonFactory {
       private static Singleton single;
       static {
          try {
             Class c = Class.forName(Singleton.class.getName());
             //获取无参构造器
             Constructor cs = c.getDeclaredConstructor();
             //设置无参构造器是可以访问的
             cs.setAccessible(true);
             //创建一个实例
             single = (Singleton)cs.newInstance();
          } catch (ClassNotFoundException e) {
             e.printStackTrace();
          } catch (NoSuchMethodException e) {
             e.printStackTrace();
          } catch (InstantiationException e) {
             e.printStackTrace();
          } catch (IllegalAccessException e) {
             e.printStackTrace();
          } catch (InvocationTargetException e) {
             e.printStackTrace();
          }
       }
       //获取单例对象的外部访问方法
       public static Singleton getSingleton(){
          return single;
       }
    }
    

    在这里主要注意单例模式下的反射影响。

    ④延迟初始化:一个对象被消费完毕后,并不立即释放,工厂类保持其初始状态,等待再次被使用。
    代码重现:

    public class ProductFactory {
       private static final Map<String,Product>PRODUCT_MAP = new HashMap<>();
       public static synchronized Product createProduct(String type)throws Exception{
          Product product = null;
          if (PRODUCT_MAP.containsKey(type)){
             product = PRODUCT_MAP.get(type);
          }else {
             if (Objects.equals(type,"Product1")){
                product = new ConcreteProduct1();
             }else {
                product = new ConcreteProduct2();
             }
             PRODUCT_MAP.put(type,product);
          }
          return product;
       }
    }
    

    ProductFactory 负责产品类对象的创建工作,并且通过 PRODUCT_MAP 变量产生一个缓存,将需要再次被使用的对象保留。

    延迟初始化框架是可以扩展的,比如限制产品的最大数量,可以通过判断map集合的大小来实现;比如JDBC连接数据库,判断最大连接数MaxConnections等

    参考书籍:设计模式之禅 --- 秦小波 著

    相关文章

      网友评论

          本文标题:设计模式 --工厂方法模式(FACTORY METHOD)

          本文链接:https://www.haomeiwen.com/subject/actqiftx.html