创建型之工厂模式

序言

  工厂模式作为创建多例对象的一种设计思想,避免了面向过程一泻千里的糟糕写法,扩展性和可维护性都很强,值得我们好好学习。
  工厂模式大致分为3类,分别是简单工厂、工厂方法、抽象工厂,下面就自己的理解,总结一下。入笔之前,先阐述几个不知所云的概念。

  • 抽象工厂类角色:接口或者抽象类,所有的具体工厂类都要实现或继承该类
  • 具体工厂类角色:具体类,new对象的逻辑都在这里,调用者只需调用该静态方法
  • 抽象产品角色:接口或者抽象类,为调用者提供行为方法
  • 具体产品角色:具体类,真正被new的对象,调用者无需亲自创建,一切皆由静态工厂方法处理

1. 简单工厂

  简单工厂的基本结构如下图:

![](http://images2017.cnblogs.com/blog/946528/201708/946528-20170808180123402-1285784484.png)

  套路:
    1. 要生成多个相似功能的产品,但不同的产品的具体功能不同,即要有继承或者实现接口
    2. 添加1个具体工厂类,添加1个静态工厂方法

/**
 * 抽象产品角色
 */
public interface Fruit {
    void grow();
}
/**
 * 具体产品角色
 */
public class Apple implements Fruit {

    public void grow() {

        System.out.println("apple growed");
    }
}
/**
 * 具体产品橘色
 */
public class Banana implements Fruit {

    public void grow() {
        System.out.println("banana growed");
    }
}
/**
 * 工厂类
 */
public class FruitFactory {

    public static Fruit createFruit(String fruitName){

        if("apple".equals(fruitName)){
            return new Apple();
        }

        if("banaa".equals(fruitName)){
            return new Banana();
        }

        throw new RuntimeException("fruitName not exits");
    }

    public static <T extends Fruit> T createFruit(Class<T> clazz){
        T fruit = null;
        try {

            fruit = (T) Class.forName(clazz.getName()).newInstance();

            return fruit;

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }
}
public class SimpleFactoryTest {

    @Test
    public void testSimpleFactory(){

        Fruit apple = FruitFactory.createFruit("apple");
        apple.grow();
        Banana banana = FruitFactory.createFruit(Banana.class);
        banana.grow();
    }
}

  吹牛:增加工厂类后,调用者无需亲自创建对象,通过静态工厂方法拿到对象后,直接调用其行为方法,如果再增加葡萄产品时,只需写一个Grape类,实现Fruit接口,在Factory增加1个if即可,无需修改客户端代码。不好的地方在于,静态工厂方法承担的任务太重,当产品越来越多时,该方法会变得又臭又长。

2. 工厂方法

  工厂方法基本结构图如下:

![](http://images2017.cnblogs.com/blog/946528/201708/946528-20170808180323370-1531403486.png)
  本文的结构图如下:
![](http://images2017.cnblogs.com/blog/946528/201708/946528-20170808180211964-2042571677.png)

套路:
  1. 要生产多个相似功能的产品,但通过分类,还可以分为几大类的生产者
  2. 添加1个抽象工厂类或者接口,添加多个具体生产工厂,工厂里的方法都是实例方法
  3. 客户端调用时,直接new对应的factory,然后传参数调用其实例方法

/**
 * 产品接口
 */
public interface Animal {
    void run();
}
/**
 * 具体产品,4条腿
 */
public class Panada implements Animal{
    public void run() {
        System.out.println("panada is running ...");
    }
}
/**
 * 具体产品,4条腿
 */
public class Tigger implements Animal{
    public void run() {
        System.out.println("tigger is running ...");
    }
}
/**
 * 具体产品,2条腿
 */
public class Human implements Animal{
    public void run() {
        System.out.println("human is runging ....");
    }
}
/**
 * 具体产品,2条腿
 */
public class Penguin implements Animal {
    public void run() {
        System.out.println("penguin is running ...");
    }
}
/**
 * 抽象工厂接口
 */
public interface AnimalFactory {
    Animal createAnimal(String animalName);
}
/**
 * 具体工厂,两条腿
 */
public class TwoLegsAnimalFactory implements AnimalFactory{

    public Animal createAnimal(String animalName) {
        if("human".equals(animalName)){
            return new Human();
        }
        if("penguin".equals(animalName)){
            return new Penguin();
        }

        throw new RuntimeException("not extists this four legs");
    }
}
/**
 * 具体工厂,4条腿
 */
public class FourLegsAnimalFactory implements AnimalFactory{

    public Animal createAnimal(String animalName) {

        if("tigger".equals(animalName)){
            return new Tigger();
        }

        if("panada".equals(animalName)){
            return new Panada();
        }

        throw new RuntimeException("not extists this four legs");
    }
}
/**
 * 测试工厂方法
 */
public class FactoryMethodTest {
    @Test
    public void testFactoryMethod(){

        AnimalFactory fourLegsAnimalFactory = new FourLegsAnimalFactory();

        fourLegsAnimalFactory.createAnimal("tigger").run();
        fourLegsAnimalFactory.createAnimal("panada").run();

        TwoLegsAnimalFactory twoLegsAnimalFactory = new TwoLegsAnimalFactory();
        twoLegsAnimalFactory.createAnimal("penguin").run();
        twoLegsAnimalFactory.createAnimal("human").run();
    }
}

  吹牛:如果系统需要增加一个新产品,那么只需要向系统增加一个具体产品类,及其对应的具体工厂类,无需修改抽象工厂类,无需修改其它具体工厂类,也无需修改客户端。

3. 抽象工厂

抽象工厂的具体结构图如下:

![](http://images2017.cnblogs.com/blog/946528/201708/946528-20170808180359105-515577390.png)

  套路:
    1. 添加新的产品,增加抽象产品,以及其对应的具体产品类
    2. 在工厂方法模式下,修改具体工厂方法名称,用产品名称命名
    3. 在抽象工厂接口里添加生产具体产品的方法

/**
 * 抽象产品-电脑
 */
public interface Computer {
    public String getComputerInfo();
}
/**
 * 抽象产品-手机
 */
public interface Phone {
    public String getPhoneInfo();
}
/**
 * 具体产品-苹果电脑
 */
public class AppleComputer implements Computer{
    public String getComputerInfo() {
        return "mac pro 12 is using";
    }
}

/**
 * 具体工厂-三星电脑
 */
public class SamsungComputer implements Computer{

    public String getComputerInfo() {
        return "samsung 900X3N-K09 is using";
    }
}
/**
 * 具体产品-苹果手机
 */
public class ApplePhone implements Phone{
    public String getPhoneInfo() {
        return "iphone 8 is using";
    }
}
/**
 * 具体产品-三星手机
 */
public class SamsungPhone implements Phone {
    public String getPhoneInfo() {
        return "samsung galaxy s8 is usging";
    }
}
/**
 * 抽象工厂
 */
public interface ElectronicFactory {
    public Phone createPhone();
    public Computer createComputer();
}
/**
 * 具体工厂-苹果,以品牌厂家分类,即apple和samsung,而不是具体产品分类,即computer和phone
 */
public class AppleFactory implements ElectronicFactory{

    public Phone createPhone() {
        return new ApplePhone();
    }

    public Computer createComputer() {
        return new AppleComputer();
    }
}
/**
 * 具体工厂-三星,以品牌厂家分类,即apple和samsung,而不是具体产品分类,即computer和phone
 */
public class SamsungFactory implements ElectronicFactory{
    public Phone createPhone() {
        return new SamsungPhone();
    }

    public Computer createComputer() {
        return new SamsungComputer();
    }
}
/**
 * 抽象工厂测试
 */
public class AbstractFactoryTest {

    @Test
    public void testAbstractFactory(){

        ElectronicFactory appleFactory = new AppleFactory();
        appleFactory.createPhone().getPhoneInfo();
        appleFactory.createComputer().getComputerInfo();

        ElectronicFactory samsungFactory = new SamsungFactory();
        samsungFactory.createPhone().getPhoneInfo();
        samsungFactory.createComputer().getComputerInfo();

    }
}

  吹牛:如果系统需要增加一个新的产品族,如新厂家或者新品牌,再增加一个品牌的具体工厂方法即可,无需修改原来的抽象工厂类和具体工厂类,也无需修改客户端,缺点是如果增加一个新的产品时,即添加一个抽象类及其对应的具体产品类的产品树时,原来的抽象工厂和具体工厂都要修改。

4. 总结

  • 简单工厂: 用来生产同一品牌下的不同但具有相似功能的产品;扩展性差,增加产品时,必须得修改原来具体工厂。
  • 工厂方法: 用来生产同一品牌下的不同中但具有相似功能的产品;扩展性强,增加产品时,不需要修改具体工厂。
  • 抽象工厂: 用来生产不同品牌下的不同但具有相似功能的产品;增加品牌时,扩展性强;增加产品时,扩展性差,必须得修改原来的抽象和具体工厂。

后记

  转载时,注明出处是人格的一种体现。
  https://www.zybuluo.com/BertLee/note/837738
  能力有限,如有纰漏,请在评论区指出,老朽虽一把年纪,必当感激涕零,泪如雨下。

posted @ 2017-08-08 17:54  吃不了兜着走  阅读(107)  评论(0编辑  收藏  举报