zoukankan      html  css  js  c++  java
  • 创建型之工厂模式

    序言

      工厂模式作为创建多例对象的一种设计思想,避免了面向过程一泻千里的糟糕写法,扩展性和可维护性都很强,值得我们好好学习。
      工厂模式大致分为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
      能力有限,如有纰漏,请在评论区指出,老朽虽一把年纪,必当感激涕零,泪如雨下。

  • 相关阅读:
    WCF中NetTCp配置
    生产者消费者模式
    MVC 引擎优化
    Wcf
    MongoDB运用
    Sock基础
    WebService
    线程
    委托
    特性
  • 原文地址:https://www.cnblogs.com/codebug/p/7308177.html
Copyright © 2011-2022 走看看