• 设计模式 01


    参考

    1. 工厂模式|菜鸟教程

    2. 三种工厂模式的分析以及C++实现|博客园

    3. 设计模式之Factory

    4. GOF design patterns | YouTube

    工厂模式

    主要分为2种:简单工厂,工厂方法。有别于抽象工厂。

    简单工厂

    client通过给SimleFactory传不同参数,由SimpleFactory根据实际情况决定如何初始化具体的Product对象。

    适用场景:替代new来创建对象;不希望client直接处理Product创建细节;Product类型比较确定,不会经常变动;Product子类可以通过同一种创建方法创建,包括传入的参数数量、类型一致;

    特点:实现简单,能对client屏蔽创建Product细节;

    缺点: 当需要增加/删除Product子类时,需要修改Factory类;当Product子类较多时,Factory容量就会很大,复杂度变高;

    通用类图:

    简单工厂举个有意思的例子(参考文档4:youtube视频):

    EnemyShipTesting(client端)要创建EnemyShip,如果没有SimpleFactory,就要在EnemyShipTesting中处理各种与EnemyShip及其子类相关的细节。而设置了EnemyShipSimpleFactory之后,这些工作细节都可以交给SimpleFactory来做,client端只用关注需要选择创建什么EnemyShip类型即可,而不用关系如何创建,也不用知道具体的EnemyShip子类。类图如下:

     

    实现代码:

    EnemyShip产品抽象类

    // EnemyShip.java
    public abstract class EnemyShip {
        private String name;
        private double amtDamage;
        
        public void setName(String newName) { name = newName; }
        public String getName() { return name; }
        
        public void setDamage(double newDamage) { amtDamage = newDamage; }
        public double getDamage() { return amtDamage; }
        
        public void followHeroShip(){
            System.out.println(getName() + " is following the hero.");
        }
        
        public void displayEnemyShip(){
            System.out.println(getName() + " is on the screen.");
        }
        
        public void enemyShipShoots(){
            System.out.println(getName() + " attacks and does " + getDamage() + " damage.");
        }
    }

    EnemyShip产品子类UFOEnemyShip

    // UFOEnemyShip.java
    public class UFOEnemyShip extends EnemyShip {
        
        public UFOEnemyShip() {
            setName("UFO Enemy Ship");
            setDamage(20.0);
        }
    
    }

    EnemyShip产品子类RocketEnemyShip

    // RocketEnemyShip.java
    public class RocketEnemyShip extends EnemyShip {
        
        public RocketEnemyShip(){
            setName("Rocket Enemy Ship");
            setDamage(10.0);
        }
    
    }

    EnemyShip产品子类BigUFOEnemyShip

    // BigUFOEnemyShip.java
    public class BigUFOEnemyShip extends EnemyShip {
        
        public BigUFOEnemyShip() {
            setName("Big UFO Enemy Ship");
            setDamage(30.0);
        }
    }

    SimpleFactory对应具体的EnemyShipSimpleFactory 

    // EnemyShipSimpleFactory.java
    public class EnemyShipSimpleFactory {
        
        // SimpleFactory 根据传入参数创建不同的EnemyShip产品对象
        public EnemyShip makeEnemyShip(String enemyShipType) {
            EnemyShip enemyShip = null;
            
            if(enemyShipType.equals("R")) {
                
                enemyShip = new RocketEnemyShip();
                
            } else if(enemyShipType.equals("U")) {
                
                enemyShip = new UFOEnemyShip();
                
            } else if(enemyShipType.equals("B")) {
                
                enemyShip = new BigUFOEnemyShip();
                
            } 
            
            return enemyShip;
        }
    }

    client对应EnemyShipTesting

    // EnemyShipTesting.java
    public class EnemyShipTesting {
    
        public static void main(String[] args) {
            
            Scanner userInput = new Scanner(System.in);
            
            System.out.println("What type of enemy?( U / R / B)");
            
            String enemyShipOption = "";
            
            EnemyShip enemyShip = null;
            
            // client 根据具体情况给SimpleFactory传送参数, 由SimpleFactory决定如何初始化具体的EnemyShip产品对象
            if (userInput.hasNextLine()    ) {
                
                enemyShipOption = userInput.nextLine();
                
                EnemyShipSimpleFactory factory = new EnemyShipSimpleFactory();
                
                enemyShip = factory.makeEnemyShip(enemyShipOption);
                
                doStuffEnemy(enemyShip);
            }
            
        }
        
        /* 
        public static void main(String[] args) {
            EnemyShip ufoShip = null;
            
            Scanner userInput = new Scanner(System.in);
            
            String enemyShipOption = "";
            
            System.out.println("What type of ship?(U / R)");
            
            // 在client中根据选择, 创建不同的EnemyShip产品对象
            if (userInput.hasNextLine()) {
                
                enemyShipOption = userInput.nextLine();
                
                if(enemyShipOption.equals("R")) {
    
                    ufoShip = new RocketEnemyShip();
    
                }else if(enemyShipOption.equals("U")) {
                    
                    ufoShip = new UFOEnemyShip();
                    
                }
                
                doStuffEnemy(ufoShip);
            }
            
        }
        */
        
        public static void doStuffEnemy(EnemyShip anEnemyShip){
            anEnemyShip.displayEnemyShip();
            anEnemyShip.followHeroShip();
            anEnemyShip.enemyShipShoots();
        }

    测试结果:

    工厂方法

    提供一个统一的抽象接口(工厂方法)用来,让(工厂)子类决定实例化哪一个类,使对象的初始化延迟到(工厂)子类进行。

    适用场景:替代new来创建对象;具体产品会经常变动(添加);

    特点:每一个具体的工厂只生产一种产品;扩展一个新产品时,只需要添加对应具体的工厂即可,而且不用修改原工厂;

    缺点:当要生成的具体产品很多时,要添加的具体工厂就会很多;

    通用类图:

     

    demo:针对上面简单工厂的例子,进行修改

    几个Product类EnemyShip, UFOEnemyShip, RocketEnemyShip, BigUFOEnemyShip可以不用变动。针对每一个Product类新添加对应的工厂类,来生产Product(一一对应)。

    EnemyShipFacotry<--> EnemyShip

    // EnemyShipFacotry.java
    public interface EnemyShipFacotry {
        public EnemyShip makeEnemyShip();
    }
    View Code

    UFOEnemyShipFactory<-->UFOEnemyShip

    // UFOEnemyShipFactory.java
    public class UFOEnemyShipFactory implements EnemyShipFacotry {
    
        @Override
        public EnemyShip makeEnemyShip(){
            return new UFOEnemyShip();
        }
    }
    View Code

    RocketEnemyShipFactory<-->RocketEnemyShip

    // RocketEnemyShipFactory.java
    public class RocketEnemyShipFactory implements EnemyShipFacotry{
    
        @Override
        public EnemyShip makeEnemyShip() {
            return new RocketEnemyShip();
        }
    }
    View Code

    BigUFOEnemyShipFactory<-->BigUFOEnemyShip

    // BigUFOEnemyShipFactory.java
    public class BigUFOEnemyShipFactory implements EnemyShipFacotry{
    
        @Override
        public EnemyShip makeEnemyShip() {
            return new BigUFOEnemyShip();
        }
    }
    View Code

    测试类EnemyShipTesting

    // EnemyShipTesting 测试类
    public class EnemyShipTesting {
    
        public static void main(String[] args) {
            EnemyShip enemyShip = null;
            
            // 创建具体的工厂模式()
            EnemyShipFacotry enemyShipFacotry = new BigUFOEnemyShipFactory();
            // 调用工厂方法创建对象
            enemyShip = enemyShipFacotry.makeEnemyShip();
            // 测试创建对象
            doStuffEnemy(enemyShip);
        }
        
        public static void doStuffEnemy(EnemyShip anEnemyShip){
            anEnemyShip.displayEnemyShip();
            anEnemyShip.followHeroShip();
            anEnemyShip.enemyShipShoots();
        }
    }
    View Code

    测试结果:生产的Product与创建的工厂方法类相符。

    小结

    1. 简单工厂没有父类,创建具体的Product对象需要用户传入不同参数;工厂模式有父类,创建具体的Product无需用户传入不同参数,只需创建不同的具体工厂对象;

    2. 工厂模式具体的子类跟产品具体子类对应关系是一一对应,即一个具体工厂只生产一种产品;

    3. 要扩展一个具体的产品对象时,只需要添加一个新的工厂;

  • 相关阅读:
    03 类与对象
    课堂作业02程序设计
    动手动脑
    做课题时的一些问题
    课题一
    《大道至简》JAVA伪代码读后感
    题目-兔子繁衍问题
    题目-求一个日期是该年中的第几天
    题目-查验身份证
    题目-删除重复字符
  • 原文地址:https://www.cnblogs.com/fortunely/p/9467177.html
Copyright © 2020-2023  润新知