工厂模式(Factory Design Patter)
2016-06-02 22:20
393 查看
什么是工厂模式?
定义一: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
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
public class UFOEnemyShip extends EnemyShip{ public UFOEnemyShip() { setName("UFO Enemy Ship"); setAmtDamage(20.0); } }
RocketEnemyShip.java
public class RocketEnemyShip extends EnemyShip{ public RocketEnemyShip() { setName("Rocket Enemy Ship"); setAmtDamage(10.0); } }
EnemyShipTesting.java
如果不用工厂模式,则如下:在代码中写死了EnemyShip,而不是动态产生。
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(); } }
如果我们想实现动态,则应该将代码改为:
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
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中调用工厂方法
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、工厂模式时典型的解耦框架。高层模块只需要知道产品的抽象类,不需要管实现,符合迪米特法则,也符合依赖倒置原则,只依赖产品的抽象类,也符合里式替换原则,使用产品子类替换父类。
用工厂方法模式的缺点
可能会增加代码的复杂度。相关文章推荐
- iOS时间个性化设置设置
- 06-Hive表属性操作
- VMware 出现“internal error”的解决办法
- 微信公众平台开发教程第1篇-新手解惑
- POJ 3329 TSP变形 / floyd预处理+状压DP
- 为外部硬件设置一键连接WiFi HF-SmartLink V7的使用
- EasyUI combobox 加载JSON数据
- mysql 创建函数set global log_bin_trust_function_creators=TRUE;
- EasyUI combobox 加载JSON数据
- EasyUI combobox 加载JSON数据
- spring HiddenHttpMethodFilter使用问题
- mysql 创建函数set global log_bin_trust_function_creators=TRUE;
- mysql 创建函数set global log_bin_trust_function_creators=TRUE;
- javascript获取某个月份(js每月天数,当月天数)的天数
- 【SQL Sever】 存储过程的创建和执行
- 知名黑客论坛Nulled.io被黑 9.45GB数据遭泄露
- 第十五周 周记
- [Spring MVC] - SpringMVC的各种参数绑定方式
- Ionic2学习笔记(7):Input
- 3225有源时钟,晶振封装管脚定义