创建型模式(2):工厂模式

定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
/** 通用源码 */
// 抽象产品类
public abstract class Product{
    // 产品类的公用方法
    public void method1(){
        // 业务逻辑
    }
    // 抽象方法
    public abstract void method2();
}

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

// 抽象工厂类
public abstract class Creator{
    // 创建一个产品对象,其输入参数可自行设置,通常为String、Enum、Class等,也可为空
    public abstract <T extends Product> T createProduct(Class<T> c);
}

// 具体工厂类
public class ConcreteCreator extends creator {
    @Override
    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;
    }
}

// 使用场景
Public class Client{
    public static void main(String[] args){
        Creator creator = new ConcreteCreator();
        Product product = creator.createProduct(ConcreteProduct1.class);
        // 其他业务逻辑。
    }
}

工厂方法模式的优点:
  • 良好的封装性,代码结构清晰;
  • 扩展性优秀;
  • 屏蔽产品类;
  • 典型的解耦框架,高层模块只需要感知产品的抽象类,其他实现不用关心,符合迪米特、依赖倒置、里氏替换。
工厂模式的使用场景:
  • 所有需要产生新对象的地方都可以使用,但需要考虑是否会增加代码复杂度;
  • 需要灵活、可扩展的框架时,可以考虑使用工厂方法模式;
  • 可以用在异构项目当中;
  • 可以使用在测试驱动开发的框架下(JMock&EasyMock的诞生使此场景弱化了,可直接使用JMock&EasyMock进行测试解耦)。
工厂模式的扩展
  • 缩小为简单工厂模式:模块只需要一个工厂类,没必要使用抽象工厂,直接去掉继承抽象类,使用实际工厂类,并将产生对象的方法静态化(static);
  • 升级为多个工厂类:当产品复杂的时候,所有产品放到一个工厂中进行初始化会使得代码结构不清晰,为使结构清晰,可以为每个产品定义一个创造者,然后调用者自己选择跟哪一个实际工厂进行关联。
  • 替代单例模式:不允许使用new产生对象,提供一个工厂使用反射生成这个对象(那其他地方也可以这样产生这个对象,可修改构造器,防止被多次调用)
  • 延迟初始化:一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用;其可降低对象的产生和销毁带来的复杂性。
// 延迟初始化示例代码
public class ProductFactory{
    private static final Map<String, Product> prMap = new HashMap();
    public static synchronized Product createProduct(String type) throws Exception{
        Product product = null;
        if (prMap.containsKey(type)){
            product = prMap.get(type);
        } else {
            if (type.equals("Product1")) {
                product = new ConcreteProduct1();
            } else {
                product = new ConcreteProduct2();
            }
            // 同时把对象放到缓存容器中
            prMap.put(type, product);
        }
        return product;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容