设计模式 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. 要扩展一个具体的产品对象时,只需要添加一个新的工厂;

原文地址:https://www.cnblogs.com/fortunely/p/9467177.html