参考
1. 工厂模式|菜鸟教程
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(); }
UFOEnemyShipFactory<-->UFOEnemyShip

// UFOEnemyShipFactory.java public class UFOEnemyShipFactory implements EnemyShipFacotry { @Override public EnemyShip makeEnemyShip(){ return new UFOEnemyShip(); } }
RocketEnemyShipFactory<-->RocketEnemyShip

// RocketEnemyShipFactory.java public class RocketEnemyShipFactory implements EnemyShipFacotry{ @Override public EnemyShip makeEnemyShip() { return new RocketEnemyShip(); } }
BigUFOEnemyShipFactory<-->BigUFOEnemyShip

// BigUFOEnemyShipFactory.java public class BigUFOEnemyShipFactory implements EnemyShipFacotry{ @Override public EnemyShip makeEnemyShip() { return new BigUFOEnemyShip(); } }
测试类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(); } }
测试结果:生产的Product与创建的工厂方法类相符。
小结
1. 简单工厂没有父类,创建具体的Product对象需要用户传入不同参数;工厂模式有父类,创建具体的Product无需用户传入不同参数,只需创建不同的具体工厂对象;
2. 工厂模式具体的子类跟产品具体子类对应关系是一一对应,即一个具体工厂只生产一种产品;
3. 要扩展一个具体的产品对象时,只需要添加一个新的工厂;