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

1.前言

直接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抽象工厂模式的类结构

由上图可知,抽象工厂AbstractFactory定义了两个方法用来获取产品族A和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");
    }
}
  • 工厂实现类
    该实现类可以创建产品族A和产品族B的一个产品,通常因为业务关系这俩会被配合起来使用,而这也是我们使用抽象工厂模式的原因。
    细心点你会发现,这不就是工厂方法模式吗?确实,抽象工厂模式底层由工厂方法模式实现,只不过相比后者它的每个工厂实现都创建了不同产品族的产品。
public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }

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

4.3抽象工厂模式的缺点

产品族的扩展非常麻烦,每当我们扩展一个产品族,也即在抽象工厂中增加一个抽象方法,必须同时修改工厂的实现类,不符合开闭原则。

总结

工厂模式按复杂程度从低到高可分为简单工厂模式,工厂方法模式和抽象工厂模式。
总的来说有两个好处。1:封装了产品创建的细节,便于后期维护 2.客户端面向接口编程,具体的产品类运行期决定,便于产品类的扩展和后期维护(简单工厂模式不具备该特性,抽象工厂产品族的扩展除外)

参考资料

  • 《设计模式之禅》
  • 《Head First 设计模式》

猜你喜欢

转载自www.cnblogs.com/takumicx/p/9275917.html