美文网首页
设计模式 --工厂方法模式(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