什么是工厂模式?
定义一: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);
}
}
如果不用工厂模式,则如下:在代码中写死了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、当需要灵活的、可扩展的框架时,可以考虑工厂模式。
工厂方法模式的优点
用工厂方法模式的缺点
可能会增加代码的复杂度。