设计模式 --并不简单的工厂模式

前言

上几节课咱们讲了单例模式,今天咱们再来说另一个比较经常使用的建立型模式:工厂模式(Factory Design Pattern)。设计模式

通常状况下,工厂模式分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。实际上,这三种咱们最经常使用得是第一种简单工厂和工厂方法模式。而抽象工厂的原理稍微复杂点,在实际的项目中相对也不经常使用。因此,咱们今天主要讲解的重点是前两种工厂模式。ide

简单工厂(Simple Factory)

// 建立抽象产品类,定义具体产品得公共接口
abstract class Product{
    public abstract void Show();
}
// 建立具体产品类(继承抽象产品类),定义生产的具体产品

//具体产品类A
class  ProductA extends  Product{
    @Override
    public void Show() {
        System.out.println("生产出了产品A");
    }
}

//具体产品类B
class  ProductB extends  Product{

    @Override
    public void Show() {
        System.out.println("生产出了产品C");
    }
}
// 建立工厂类,经过建立静态方法从而根据传入不一样参数建立不一样具体产品类的实例
class  Factory {
    public static Product Manufacture(String ProductName){
//工厂类里用switch语句控制生产哪一种商品;
//使用者只须要调用工厂类的静态方法就能够实现产品类的实例化。
        switch (ProductName){
            case "A":
                return new ProductA();
            case "B":
                return new ProductB();
            default:
                return null;

        }
    }
}

能够看到,对于上面得简单工厂的实现方法,若是咱们要添加新的Product,那势必要改动到 Factory 的代码,那这是否是违反开闭原则呢?实际上,若是不是须要频繁地添加新的 Product,只是偶尔修改一下Factory代码,稍微不符合开闭原则,也是彻底能够接受的。函数

除此以外,在 Factory 有一组 if 分支判断逻辑,是否是应该用多态或其余设计模式来替代呢?实际上,若是 if 分支并非不少,代码中有 if 分支也是彻底能够接受的。应用多态或设计模式来替代 if 分支判断逻辑,也并非没有任何缺点的,它虽然提升了代码的扩展性,更加符合开闭原则,但也增长了类的个数,牺牲了代码的可读性。学习

总结一下,尽管简单工厂模式的代码实现中,有多处 if 分支判断逻辑,违背开闭原则,但权衡扩展性和可读性,这样的代码实如今大多数状况下(好比,不须要频繁地添加 Product,也没有太多的 Product)是没有问题的。设计

工厂方法(Factory Method)

//建立抽象工厂类,定义具体工厂的公共接口
abstract class IFactory{
    public abstract Product Manufacture();
}

//工厂A类 - 生产A类产品
class  FactoryA extends IFactory{
    @Override
    public Product Manufacture() {
        return new ProductA();
    }
}

//工厂B类 - 生产B类产品
class  FactoryB extends IFactory{
    @Override
    public Product Manufacture() {
        return new ProductB();
    }
}

实际上,这就是工厂方法模式的典型代码实现。这样当咱们新增一种 Product 的时候,只须要新增一个实现了 IFactory 接口的 Factory 类便可。因此,工厂方法模式比起简单工厂模式更加符合开闭原则。code

看似很完美了,可是这里仍是有一些小问题,简单工厂只是把麻烦的if判断从工厂类,移交到了使用者手里,怎么说呢?来看下面这段代码对象

//生产工做流程
public class FactoryPattern {
    public static void main(String[] args){
        //客户要产品A
        Product mFactoryA = load("A");
        mFactoryA.Manufacture().Show();

        //客户要产品B
        Product mFactoryB = load("A");
        mFactoryB.Manufacture().Show();
    }
    
    

  public IFactory load(String factoryType) {

    IFactory factory = null;
    if ("A".equalsIgnoreCase(factoryType)) {
      factory = new FactoryA();
    } else if ("B".equalsIgnoreCase(factoryType)) {
      factory = new FactoryB();
    } else {
      throw new InvalidRuleConfigException("factoryType is not supported: " + factoryType);
    }

    return factory;
  }
}

从上面的代码实现来看,工厂类对象的建立逻辑又耦合进了 load() 函数中,跟咱们最初的代码版本很是类似。假如咱们的业务需求是,根据读取的配置文件来建立相应的Product,其实不论是简单工厂模式仍是方法工厂模式,上诉的if判断都没法消灭掉(因此在 GoF 的《设计模式》一书中,它将简单工厂模式看做是工厂方法模式的一种特例继承

抽象工厂(Abstract Factory)

讲完了简单工厂、工厂方法,咱们再来看抽象工厂模式。抽象工厂模式的应用场景比较特殊,没有前两种经常使用,不是咱们学习的重点,咱们来简单了解一下就好了。接口

咱们这里有一个需求场景,有一个工厂,他主要生产容器和模具。对于容器和模具下面又分不少种类。以下:工作流

// 容器
ContainerProductA 
ContainerProductB

//模具
MouldProductA
MouldProductB

针对这种特殊的场景,若是仍是继续用工厂方法来实现的话,咱们要针对每一个产品 都编写一个工厂类,也就是要编写 4 个工厂类。若是咱们将来还须要增长了其余类型的生产产品(好比 杯子),那就要再对应地增长 2 个工厂类。而咱们知道,过多的类也会让系统难维护。这个问题该怎么解决呢?

抽象工厂就是针对这种很是特殊的场景而诞生的。咱们可让一个工厂负责建立多个不一样类型的对象(容器、模具、杯子 等),而不是只建立一种 Product 对象。这样就能够有效地减小工厂类的个数。具体的代码实现以下所示:

//建立抽象工厂类,定义具体工厂的公共接口
abstract class Factory{
   public abstract Product ManufactureContainer();
    public abstract Product ManufactureMould();
}
//建立抽象产品族类 ,定义具体产品的公共接口;
abstract class AbstractProduct{
    public abstract void Show();
}
//容器产品抽象类
abstract class ContainerProduct extends AbstractProduct{
    @Override
    public abstract void Show();
}

//模具产品抽象类
abstract class MouldProduct extends AbstractProduct{
    @Override
    public abstract void Show();
}
//容器产品A类
class ContainerProductA extends ContainerProduct{
    @Override
    public void Show() {
        System.out.println("生产出了容器产品A");
    }
}

//容器产品B类
class ContainerProductB extends ContainerProduct{
    @Override
    public void Show() {
        System.out.println("生产出了容器产品B");
    }
}

//模具产品A类
class MouldProductA extends MouldProduct{

    @Override
    public void Show() {
        System.out.println("生产出了模具产品A");
    }
}

//模具产品B类
class MouldProductB extends MouldProduct{

    @Override
    public void Show() {
        System.out.println("生产出了模具产品B");
    }
}
//A厂 - 生产模具+容器产品
class FactoryA extends Factory{

    @Override
    public Product ManufactureContainer() {
        return new ContainerProductA();
    }

    @Override
    public Product ManufactureMould() {
        return new MouldProductA();
    }
}

//B厂 - 生产模具+容器产品
class FactoryB extends Factory{

    @Override
    public Product ManufactureContainer() {
        return new ContainerProductB();
    }

    @Override
    public Product ManufactureMould() {
        return new MouldProductB();
    }
}

总结

咱们来一块总结回顾一下,这里的三种工厂模式中,简单工厂和工厂方法比较经常使用,抽象工厂的应用场景比较特殊,因此不多用到,其实了解一下就能够了。

当建立逻辑比较复杂,是一个“大工程”的时候,咱们就考虑使用工厂模式,封装对象的建立过程,将对象的建立和使用相分离。何为建立逻辑比较复杂呢?

  • 代码中若是存在 if-else分支判断,动态地根据不一样的类型建立不一样的对象。针对这种状况,咱们就考虑使用工厂模式,将这一大坨if-else建立对象的代码抽离出来,放到工厂类中。
  • 还有一种状况,就是对象的建立十分复杂,咱们也可使用工厂类的方式来屏蔽对象的建立细节(建造者模式也是解决该类问题),在这种状况下,咱们也能够考虑使用工厂模式,将对象的建立过程封装到工厂类中

对于第一种状况,当每一个对象的建立逻辑都比较简单的时候,推荐使用简单工厂模式,将多个对象的建立逻辑放到一个工厂类中。

当每一个对象的建立逻辑都比较复杂的时候,为了不设计一个过于庞大的简单工厂类,推荐使用工厂方法模式,将建立逻辑拆分得更细,每一个对象的建立逻辑独立到各自的工厂类中。

仍是那句话,不要为了使用设计模式而用设计模式,设计模式都是在相应的使用场景下而诞生的。

相关文章
相关标签/搜索