设计模式——工厂方法

83 阅读3分钟

一、定义

一个用于创建对象的接口,让子类决定实例化哪一个类。
工厂方法使一个类的实例化延迟到子类。

二、通用代码

  1. 抽象产品类
public abstract class Product{
    public void method1(){
        //业务逻辑
    }
    public abstract void method2();
}
  1. 具体产品类
public class ConcreteProduct1 extends Product{
    public void method2(){
        //业务逻辑1
    }
}
public class ConcreteProduct2 extends Product{
    public void method2(){
        //业务逻辑2
    }
}
  1. 抽象工厂类
public abstract class Creator(
    //注:参数通常为String,Enum,Class等,也可为空
    public abstract <T extends Product> T createProduct(Class<T> C);
}
  1. 具体工厂类
public class ConcreteCreator extends Creator{
    public <T extends Product> T createProduct(Class<T> C){
        Product product = null;
        try{
            product = (Product)Class.forName(c.getName()).newInstance();
        }catch(Exception e){
            //异常处理
        }
        return (T)product;
    }
}
  1. 场景调用
public Class Client{
    public static void main(String[] args){
        Creator creator = new ConcreteCreator();
        
        Product product = creator.createProduct(ConcreteProduct1.class);
    }
}

三、 优点

  1. 良好的封装性。代码结构清晰,调用者仅需知道类名,不需要管创建对象的过程如何如何。
  2. 优秀的扩展性
  3. 可以屏蔽产品类。只要接口保持不变,上层模块代码不发生改变,调用者无需在意产品类的变化。
  4. 典型的解耦框架

四、缺点

  1. 增加系统中类的数量,增加代码的复杂度
  2. 引入了抽象层,导致系统可读性较差
  3. 类层次过多,导致系统设计较为复杂

五、使用场景

  1. 生成对象的地方均可使用
    • 原因:工厂模式是new一个对象的替代品
    • 注意:增加工厂类会增加代码的复杂度,请结合实际情况,慎重考虑使用
  2. 需要灵活的,可扩展的框架
  3. 异构项目中
  4. 测试驱动开发的框架

    场景:测试一个类A,需要把类A有关联的类B同时生产处理,可以使用工厂方法模式把类B虚拟处理,避免类A与类B的耦合。
    但目前可以直接考虑JMock或EasyMock

六、扩展

  1. 简单工厂模式(静态工厂模式)

    • 方法:去掉抽象工厂类,工厂类中的方法改为静态方法
    • 优点:用法简单,调用简单,简化了类的创建过程
    • 缺点:工厂类扩展难
  2. 多工厂模式

    • 方法:给每个产品创建一个工厂抽象类
    • 优点:符合单一职责原则,职责清晰;结构简单
    • 缺点:对可扩展性和后期维护不友好
    • 注:在实际的复杂应用中,一般采用多工厂方法,增加一个协调类,封装子工厂类,对高层模块提供统一的访问接口,避免调用者与各个子工厂交流
  3. 替代单例模式

  4. 延迟初始化

    • 方法:在工厂类中定义一个Map容器,容纳产生的对象,已有的对象直接取出,没有则创建并放入Map中
    • 优点:
      • 保留需要再次被重用的对象
      • 在对象初始化比较复杂的情况下,降低对象的产生和销毁带来的复杂性
    • 扩展:控制某个产品类的最大实例化数量
    • 注意:工厂类中的生产产品的方法需要使用synchronized关键字,防止线程不安全