设计模式 - 工厂模式

282

一、原始创建

需求

客户端需要创建相应的商品,对商品做一些事,例如买卖商品等

创建方式

抽象商品:

public interface Product {
    void sell();
}

实现商品:

public class Product1 implements Product {
    @Override
    public void sell() {
        System.out.println("I am product1 and I sell for 1 dollar");
    }
}
public class Product2 implements Product {
    @Override
    public void sell() {
        System.out.println("I am product2 and I sell for 2 dollar");
    }
}

在客户端直接创建商品:

public class RawClient {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int type = sc.nextInt();
        sc.close();

        Product product;

        if (type == 1) {
            product = new Product1();
        } else if (type == 2) {
            product = new Product2();
        }

        // take product do something other here... like product.sell();

    }
}

问题

客户端往往是多个的, 如果 Product 相关需求改了

例如不只是两个, 要创建三个, 那么每一个客户端类都要加个 else if , 在上面的代码中需要加上 else if(type == 3) , 如果是要创建四个,那就要加上 else if(type == 4) 了...

问题抽象

问题的根本是创建部分的代码和调用类耦合度过高

二、简单工厂创建

创建方式

工厂类创建

工厂创建:

public class SimProductFactory {
    public Product createProduct(int type) {
        if (type == 1) {
            return new Product1();
        } else if (type == 2) {
            return new Product2();
        } else {
            throw new RuntimeException("None this type yet");
        }
    }
}

客户端使用工厂:

public class SimFacClient {
    public static void main(String[] args) {

        SimProductFactory factory = new SimProductFactory();

        Product product = factory.createProduct(1);

        // do something to porduct, like sell() ... 

    }

}

解决

解决在客户端类创建对象耦合度过高的问题

当要添加新的实体类时只需在工厂类修改即可, 不需要知道子类具体细节了

问题

问题 1 : 想要添加新的创建实体类, 就要修改工厂类

问题 2 : 若工厂类添加新的创建实体类越来越多, 导致工厂类代码臃肿难以维护

问题抽象

问题的根本就是简单工厂不符合开闭设计原则

PS : 这种问题是由于要创建的物品实体类过多才出现的,要是少量的实体类,简单工厂用起来没啥问题的!

三、工厂方法创建

创建方式

工厂类创建,但这次有多个工厂, 客户端决定在哪个工厂类创建

抽象出工厂:

public abstract class Factory {
    public abstract Product createProduct();
}

实现创建商品 1 的工厂:

public class Prod1Factory extends Factory {
    @Override
    public Product createProduct() {
        return new Product1();
    }
}

实现创建商品 2 的工厂:

public class Prod2Factory extends Factory {
    @Override
    public Product createProduct() {
        return new Product2();
    }
}

商品在工厂类创建,但由客户端决定在哪个工厂创建:

public class FactMethodClient {
    public static void main(String[] args) {

        Factory factory1 = new Prod1Factory();
        Factory factory2 = new Prod2Factory();

        Product product1 = factory1.createProduct();
        Product product2 = factory2.createProduct();

        // do something here to product1 or product2, like sell()...

    }
}

解决

工厂方法之所以叫工厂方法,原因有二:

  1. 抽象了创建物品的工厂
  2. 抽象了工厂创建物品的方法

可以,看到它统一了创建物品的方法,要创建物品,创建一个该物品的工厂,实现创建物品的创建方法就好了,它解决了简单工厂的开闭原则问题,添加新的物品,添加对应的新物品的工厂类即可,原工厂不用修改

问题

无法解决产品族生成问题, 会导致工厂类代码过多

例如, 假设生产 Product1 它其实有一类具有共同特征的不同产品,是一个系列, 旗下有 Product1A、Product1B、Product1C、Product1D、Product1E、Product1F;生产的 Product2 它其实也是一个系列,旗下有 Product2A、Product2B、Product2C、Product2D...

这可能不大好理解:

例如,我们要卖水杯,有便宜的、一般贵、很贵的... 我们要卖苹果,也有便宜、一般贵、很贵的,所以抽象一下,便宜的商品是一族,一般贵的商品是一族、很贵的商品是一族

那么这个时候要给每个物品来一个工厂类么?那未免也太多了,如何解决?

问题抽象

最根本的问题就是由于产品族的出现,使得工厂方法的抽象度不够高,导致工厂类过多

PS : 这种问题是由于产品族的出现才有的,如果不出现产品族,工厂方法完全问题!

四、抽象工厂创建

针对产品族问题出现,它们都有共同特征,例如

  • 游戏:有便宜、一般贵、很贵的等级

  • 苹果:有便宜、一般贵、很贵的等级

游戏族和苹果族是不一样的,我们需要抽象出族与族直接共同的特征:便宜、一般贵、很贵

那么练习我们的举例与 product,这里简单地,就取前两个作为代表转换一下:

  • product - 商品

    • productA - 很贵的商品
    • productB - 一般贵的商品
  • product1 - 游戏

    • product1A - 便宜的游戏
    • product1B - 一般贵的游戏
  • product2 - 苹果

    • product2A - 便宜的苹果
    • product2B - 一般贵的苹果

在工厂方法中,我们要创建 product1A 、product1B 、product2A 、product2B 需要四个工厂,但实际上不管属于 A 还是 B 它们终究还是 product1 或者 product2,逻辑上来看,有这两个工厂就足够了

那么,接下来开始依次抽象与创建工厂!

创建方式

依次抽象商品族的共有特征:

public abstract class ProductA {
    public abstract void sell();
    public abstract void decribe();
}
public abstract class ProductB {
    public abstract void sell();
    public abstract void describe(); 
}

实现各族不同特征的商品:

族1的商品:

public class Product1A extends ProductA{
    @Override
    public void decribe() {
        System.out.println("This is product1A");
    }

    @Override
    public void sell() {
        System.out.println("This product sell for A-type price which is 1.1 dollar");
    }

}
public class Product1B extends ProductB{

    @Override
    public void sell() {
        System.out.println("This is product1B");
    }

    @Override
    public void describe() {
        System.out.println("This product sell for B-type price which is 11 dollar");
    }

}

族2 的商品:

public class Product2A extends ProductA {
    @Override
    public void decribe() {
        System.out.println("This is product2A");
    }
    @Override
    public void sell() {
        System.out.println("This product sell for A-type price which is 1 dollar");
    }
}
public class Product2B extends ProductB{

    @Override
    public void sell() {
        System.out.println("This is product2B");
    }

    @Override
    public void describe() {
        System.out.println("This product sell for B-type price which is 10 dollar");
    }
    
}

抽象出工厂类的共有特征:

public abstract class Factory {
    public abstract ProductA createProductA();
    public abstract ProductB createProductB();
}

依次实现创建各族的工厂类:

public class Prod1Factory extends Factory {

    @Override
    public ProductA createProductA() {
        return new Product1A();
    }

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

}
public class Prod2Factory extends Factory {

    @Override
    public ProductA createProductA() {
        return new Product2A();
    }

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

}

在客户端创建各族的商品:

public class AbstactFacClient {
    public static void main(String[] args) {

        Prod1Factory factory1 = new Prod1Factory();
        Prod2Factory factory2 = new Prod2Factory();

        ProductA product1a = factory1.createProductA();
        ProductB product1b = factory1.createProductB();

        ProductA product2a = factory2.createProductA();
        ProductB product2b = factory2.createProductB();

        // do something here to product1a product1b product2a product2b ...

    }
}

解决

解决了由于产品族的出现,使得创建同一族的产品,但因为特征不同就要多设立一个工厂类导致工厂类过多的问题,抽象工厂使得每一族代表的一类产品,一族的许多产品对应一个工厂,大大减少了工厂类数量

问题

问题就是当产品族问题不存在,硬要使用抽象工厂,会显得代码更多,没有必要

问题抽象

说到底,抽象工厂是只适用于产品族问题的情况的,没用这个问题就不要用

五、总结

数量关系

通俗地说(写了好多,还是画图吧!)

  • 简单工厂

    商品 - 工厂 :多对一

  • 工厂方法

    商品 - 工厂 :一对一

  • 抽象工厂

    商品族 - 工厂 :一对一

适用场景

  • 简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)
  • 工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品)
  • 抽象工厂 :用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)

学习有感

感觉,简单工厂,工厂方法好理解点,就是名字有点奇怪,而抽象工厂... 无非就是名字更奇怪了,这个设计模式在使用的时候,大量用到了抽象和多态上转型,所以早期学习由于这两个理解地不好,导致设计模式总是学不懂,原因在此!

在这总结一下抽象的视图... 想一下(emm,还是写了很多,还是画图吧)

  • 简单工厂的应用,至少需要对产品做抽象

    • Product : product 的共有信息,像可以显示描述 describe() 和卖掉 sell()

  • 工厂方法的应用,需要对工厂和产品做抽象

    • Product : product 的共有信息,像可以显示描述 describe() 和卖掉 sell()

    • Factory:factory 的共有信息,像可以创建产品 createProduct()

    • PS : 多态的强大体现于此,因为 Factory 创建的时候返回类型是 Product,子类 factory 返回类型对应的是具体的 product

  • 抽象工厂的应用,需要对产品族和工厂做抽象

    • ProductA :product 族 1 2 3 的共有特征 A 的抽象
    • ProductB:product 族 1 2 3 的共有特征 B 的抽象
    • Factory:product 族 1 2 3 的 factory 的创建抽象,可以创建 ProductA 和 ProductB 的对象

从中,不禁感叹,能够熟练地运用抽象,是一种很强的能力,像抽象工厂,使用抽象,本来要创建六个的工厂,先在只需创建 3 个了,直接减少了一半;但对于族 1 2 3 这三个族,工厂数量再少也不能少于 3 ,因为一个族至得一个工厂,两个族使用同一个工厂,那跟简单工厂不就一样了?!

六、参考