创建和使用解耦——工厂模式详解(简单工厂+工厂方法+抽象工厂)


直接new一个对象是最简单的创建对象的方式,但大量出现在业务代码中会带来至少两个问题。1:创建对象的细节直接暴露在业务代码中,修改实现细节必须修改相关的大量客户端代码。2:直接面向具体类型编程,违反了面向接口编程的原则,系统进行扩展时也不得不进行大量修改。要使得系统具有的良好的可扩展性以及后期易于维护,必须实现对产品的获取和对产品的使用解耦。要做到这两点,首先要对客户端代码屏蔽掉创建产品的细节,其次,客户端必须面向产品的抽象编程,利用java的多态特性在运行时才确定具体的产品。而这,正式本篇我们要讲的工厂模式的关键。工厂模式根据创建的产品特性又可以分为工厂方法模式和抽象工厂模式,下面我们就详细讲讲它们的特点以及区别。

2. 工厂方法模式

2.1工厂方法模式的定义

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

2.2 工厂方法的类结构

2.3工厂方法模式实现

  • 创建抽象产品接口
public interface Product {

    void doSome();
}

  • 创建产品1
public class ConcreteProduct1 implements Product {
    @Override
    public void doSome() {
        System.out.println("ConcreteProduct1");
    }
}
  • 创建产品2
public class ConcreteProduct2 implements Product {
    @Override
    public void doSome() {
        System.out.println("ConcreteProduct2");
    }
}
  • 创建产品3
public class ConcreteProduct3 implements Product {
    @Override
    public void doSome() {
        System.out.println("ConcreteProduct3");
    }
}
  • 创建抽象工厂类
public abstract class AbstractFactory {
    
    public abstract Product createProduct();
}
  • 创建工厂类1,生产产品1
public class ProductFactory1 extends AbstractFactory {
    @Override
    public Product createProduct() {
        return new ConcreteProduct1();
    }
}
  • 创建工厂类2,生产产品2
public class ProductFactory1 extends AbstractFactory {
    @Override
    public Product createProduct() {
        return new ConcreteProduct1();
    }
}

  • 创建工厂类3,生产产品3
public class ProductFactory3 extends AbstractFactory {
    @Override
    public Product createProduct() {
        return new ConcreteProduct3();
    }
}

  • 测试
public class TestCase {

    public static void main(String[] args) {

        AbstractFactory factory=new ProductFactory1();

        Product product = factory.createProduct();

        product.doSome();

    }
}
  • 结果

这里只要将父类引用指向不同的工厂实现,就可以获得不同的产品类型,下面代码是通过工厂1创建了常品1,要想创建其他产品只要new 出不同的工厂就行,其他代码都不用变。咦?怎么还是需要new,这和直接new一个产品有区别吗?这里为了作演示进行了简化,实际上我们如果创建对象经常会进行一系列初始化操作,这些如果写在客户端代码里对以后维护和扩展来说简直是灾难,而现在所有这些都在客户端代码里被屏蔽了。其次如果使用过Spring框架的话就知道,对于工厂这种实例,我们可以交给框架帮我们创建并注入到所需的地方,而这时候你想要在客户端代码中获取不同的产品实例只需要修改下框架的配置参数,实现了和业务代码的完全解耦,为以后产品的扩展带来了极大的方便。

3. 简单工厂模式

简单工厂模式,顾名思义,是对工厂方法模式的简化。简单工厂模式将对所有产品的创建过程都封装在一个方法中。因为其只有一个工厂的实现类,连抽象工厂都可以省了。下面是简单工厂模式的一种实现

public class SimpleFactory {


    public static <T extends Product> Product createProduct(Class<T> clazz){

        if(clazz.equals(ConcreteProduct1.class)){
            return new ConcreteProduct1();
        }else if(clazz.equals(ConcreteProduct2.class)){
            return new ConcreteProduct2();
        }else if(clazz.equals(ConcreteProduct3.class)){
            return new ConcreteProduct3();
        }
        throw new IllegalArgumentException("参数错误!");

    }

}

因为方法是静态的,连工厂创建都省了,代码也很清晰,根据方法的参数选择实例化哪个产品类。那么简单工厂模式相比工厂方法模式有哪些缺点和优点呢?

  • 优点
    实现简单,类结构清晰

  • 缺点
    产品扩展困难,不符合开闭原则
    工厂方法模式要增加一种产品实现时,只要添加产品类和对应的工厂类,几乎不用改变原有代码。而工厂方法模式则需要修改工厂方法,添加一种创建产品的逻辑,修改了原有代码,不符合开闭原则。

4. 抽象工厂模式

4.1 抽象工厂模式的定义

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。

4.2 抽象工厂模式的类结构

上图定义了有两个产品等级和两个产品家族的抽象工厂模式的UML图。抽象工厂AbstractFactory定义了两个抽象方法,分别用来生产产品A和产品B,具体工厂ConcreteFactory1生产产品族为1的产品(产品等级1的A产品和产品等级1的B产品),而ConcreteFactory2生产产品族为2的产品(产品等级为2的A产品和产品等级为2的B产品),为了更好的解释产品等级和产品族的概念,举一个造汽车的例子。汽车可以简化为发动机+座椅+轮子。那么发动机,座椅,轮子就是产品,它们组成一个产品族。为什么?因为这些产品之间有联系,联系就是它们可以组成汽车。每种产品又有高中低三种不同的档次,那么就可以组成高中低不同档次的汽车。

  • 高档汽车产品族:高档发动机+高档座椅+高档轮子
  • 中档汽车产品族:中档发动机+中档座椅+中档轮子
  • 低档汽车产品族:低档发动机+低档座椅+低档轮子

4.3 抽象工厂模式实现

  • 抽象工厂
public interface AbstractFactory {

    //创建A产品
    ProductA createProductA();
    
    //创建B产品
    ProductB createProductB();
}

  • 产品A接口及其实现类
public interface ProductA {

    void doSome();

}
public class ProductA1 implements ProductA {
    @Override
    public void doSome() {
        System.out.println("ProductA1");
    }
}
public class ProductA2 implements ProductA {
    @Override
    public void doSome() {
        System.out.println("ProductA2");
    }
}
  • 产品B接口及其实现类
public interface ProductB {

    void doSome();
}
public class ProductB1 implements ProductB {
    @Override
    public void doSome() {
        System.out.println("ProductB1");
    }
}
public class ProductB2 implements ProductB {
    @Override
    public void doSome() {
        System.out.println("ProductB2");
    }
}
  • 工厂实现类
    该实现类创建产品族为1的产品(产品等级为1的产品A和产品等级为1的产品B)
public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB1();
    }
}

4.4 抽象工厂模式的优缺点

  • 优点
    工厂方法模式一个具体工厂创建一个具体产品,而抽象工厂模式一个具体工厂创建一个产品族的产品,适合有多个业务品种业务分类是的场景。方便添加一个产品族,只要增加一个具体的工厂,符合开闭原则。
  • 类结构复杂,不易于理解。添加产品困难,这后你需要修改几乎所有的工厂类,不符合开闭原则且不利于维护。

5. 总结

工厂模式按复杂程度从低到高可分为简单工厂模式,工厂方法模式和抽象工厂模式。下面总结下其使用场景

  • 简单工厂模式
    工厂方法的简化版。简单实用,但是产品扩展时不符合开闭原则。

  • 工厂方法模式
    生产一个具体产品,产品类型的扩展符合开闭原则,但比起简单工厂模式增加了一定复杂度。

  • 抽象工厂模式
    生产一族具体的产品。方便增加产品族但是不方便增加产品。抽象工厂模式中隐含了工厂方法模式的实现。

posted @ 2018-07-06 23:28  takumiCX  阅读(1263)  评论(0编辑  收藏  举报