前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >工厂模式(Factory Design Patter)

工厂模式(Factory Design Patter)

作者头像
刘开心_1266679
发布2019-02-14 15:21:11
3690
发布2019-02-14 15:21:11
举报

什么是工厂模式?

定义一:Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. (定义一个创建对象的接口,但是让子类决定实例化哪个类。工厂方法让类的实例化延迟到了子类)

定义二:When a method returns one of several possible classes that share a common super class. The class is chosen at runtime. (有一个方法,它返回的是拥有共同父类的子类中的一个。这个子类是在运行时被实例化的。

我的理解:工厂方法是一个能动态生产出我们需要的对象的方法,比如有ABCD四个子类,如果用户输入A,工厂方法就产生A对象,用户输入B,工厂就产生B对象,这些对象的生成是动态的,而不是事先在程序里写死了的。

工厂模式举例

代码来自Youtube视频Design Pattern Tutorial 5,链接忘了……

例子描述:

有一个负责生产敌人飞船的工厂,EnemyShip是父类,有UFOEnemyShip、RocketEnemyShip两个子类,用户输入U,则生产UFOEnemyShip,输入R,则生产RocketEnemyShip。

UML类图:

EnemyShip.java

代码语言:javascript
复制
public abstract EnemyShip {

    private String name;
    private Double amtDamage;

    public void setName(String name) {
        this.name = name;
    }
    
    public void setAmtDamage(Double amtDamage) {
        this.amtDamage = amtDamage;
    }

    public String getName() {
        return name; 
    }
 
    public Double getAmtDamage() {
        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 enemyShipShoot() {
        System.out.println(getName() + " attack and does " + getAmtDamage());
    }

}

UFOEnemyShip.java

代码语言:javascript
复制
public class UFOEnemyShip extends EnemyShip{
    public UFOEnemyShip() {
        setName("UFO Enemy Ship");
        setAmtDamage(20.0);
    }
}

RocketEnemyShip.java

代码语言:javascript
复制
public class RocketEnemyShip extends EnemyShip{
    public RocketEnemyShip() {
        setName("Rocket Enemy Ship");
        setAmtDamage(10.0);
    }
}

EnemyShipTesting.java

如果不用工厂模式,则如下:在代码中写死了EnemyShip,而不是动态产生。

代码语言:javascript
复制
public class EnemyShipTesting {

    public static void main(String[] args) {
        EnemyShip ufoShip = new UFOENemyShip();
        doStuffEnemy(ufoShip);
    }

    public static void doStuffEnemy(EnemyShip enemyShip) {
        enemyShip.displayEnemyShip();
        enemyShip.followHeroShip();
        enemyShip.enemyShipShoot();
    }
}

如果我们想实现动态,则应该将代码改为:

代码语言:javascript
复制
public class EnemyShipTesting {

    public static void main(String[] args) {
        EnemyShip theEnemy = null;
        Scanner userInput = new Scanner(System.in);
        String enemyShipOpt = "";
        System.out.println("What type of ship? U/R");
        if (userInput.hasNextLine()) {
             enemyShipOpt = userInput.nextLine();
        }
        if (userInput.equals("U")) {
             theEnemy = new UFOEnemyShip();
        } else if (userInput.equals("R")) {
             theEnemy = new RocketEnemyShip();
        } else {
             System.out.println("please input U/R next time");
        }
        doStuffEnemy(theEnemy);
    }

    public static void doStuffEnemy(EnemyShip enemyShip) {
        enemyShip.displayEnemyShip();
        enemyShip.followHeroShip();
        enemyShip.enemyShipShoot();
    }
}

但是上面的代码不符合开闭原则,没有对修改close,所以我们再次修改代码为:

1、添加EnemyShipFactory类

EnemyShipFactory.java

代码语言:javascript
复制
public class EnemyShipFactory {
    public EnemyShip makeEnemyShip(String shipType) {
        if (shipType.equals("U")) {
            return new UFOEnemyShip();
        } else if (shipType.equals("R")) {
            return new RocketEnemyShip();
        } else {
            return null;
        }
    }
}

2 、在main中调用工厂方法

代码语言:javascript
复制
public class EnemyShipTesting {

    public static void main(String[] args) {
        EnemyShipFactory shipFactory = new EnemyShipFactory();
        EnemyShip theEnemy = null;
        Scanner userInput = new Scanner(System.in);
        String enemyShipOpt = "";
        System.out.println("What type of ship? U/R");
        if (userInput.hasNextLine()) {
             enemyShipOpt = userInput.nextLine();
             theEnemy = shipFactory.makeEnemyShip(enemyShipOpt);
        }
        if (theEnemy != null) {
            doStuffEnemy(theEnemy);
        } else {
            System.out.println("please input U/R next time");
        }
    }

    public static void doStuffEnemy(EnemyShip enemyShip) {
        enemyShip.displayEnemyShip();
        enemyShip.followHeroShip();
        enemyShip.enemyShipShoot();
    }
}

什么时候使用工厂模式?

1、当你需要动态地创建子类对象的时候,如上例。

2、工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码复杂度。

3、当需要灵活的、可扩展的框架时,可以考虑工厂模式。

工厂方法模式的优点

1、良好的封装性,代码结构清晰。一个对象创建是有约束条件的,如一个调用者需要一个具体的产品对象,只要知道类名(或约束字串)就可以了,不用知道过程,降低模块间的耦合性。

2、工厂模式的扩展性非常优秀,在增加产品类的情况下,只要适当地修改具体的工厂类,或扩展一个工厂类,就可以拥抱变化。

3、工厂模式时典型的解耦框架。高层模块只需要知道产品的抽象类,不需要管实现,符合迪米特法则,也符合依赖倒置原则,只依赖产品的抽象类,也符合里式替换原则,使用产品子类替换父类。

用工厂方法模式的缺点

可能会增加代码的复杂度。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年06月02日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是工厂模式?
  • 工厂模式举例
  • 什么时候使用工厂模式?
  • 工厂方法模式的优点
  • 用工厂方法模式的缺点
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档