说明:本文介绍设计模式中,创建型设计模式中的工厂模式;
飞机大战
创建型设计模式,关注于对象的创建,本文介绍的简单工厂和工厂模式同样也是。举一个游戏例子,如飞机大战游戏中,屏幕中敌人类型有坦克、飞机,会随机出现在画面的上方;
我们可以简单的将敌人抽象为一个抽象类,然后分别创建对应的实现类,如下:
(敌人抽象类,注意属性的修饰符,protected,子类中需要用到)
/*** 敌人抽象类*/
public abstract class Enemy {/*** 敌人的坐标*/protected int x;/*** 敌人的坐标*/protected int y;/*** 抽象方法*/public Enemy(int x, int y) {this.x = x;this.y = y;}/*** 绘制方法*/public abstract void show();
}
(具体实现类,坦克)
/*** 坦克*/
public class Tank extends Enemy{public Tank(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("坦克出现了,坐标是:" + x + "," + y);}
}
(具体实现类,飞机)
/*** 飞机*/
public class AirPlane extends Enemy{public AirPlane(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("飞机出现了,坐标是:" + x + "," + y);}
}
(客户端,client)
import java.util.Random;/*** 客户端*/
public class Client {public static void main(String[] args) {// 屏幕宽度是100int screenLength = 100;// 创建坦克Enemy tank = new Tank(new Random().nextInt(screenLength),0);tank.show();// 创建飞机Enemy airPlane = new AirPlane(new Random().nextInt(screenLength),0);airPlane.show();}
}
执行结果:
分析:以上创建方式,有两点不足之处,对象的创建和使用在一起,耦合性太高;创建对象的代码放到了客户端类里,如果需要创建多个对象的话,客户端的代码势必会越来越臃肿。
简单工厂
为了解决上面提到的两个问题,耦合性高,客户端代码臃肿,我们可以使用简单工厂对上面的流程进行改进。如下,创建一个简单工厂类,将创建对象的步骤抽取到这里面:
import java.util.Random;/*** 简单工厂*/
public class SimpleFactory {/*** 屏幕宽度*/private int screenLength;/*** 随机数*/private Random random;/*** 构造函数** @param screenLength*/public SimpleFactory(int screenLength) {this.screenLength = screenLength;this.random = new Random();}/*** 创建敌人* @param type* @return*/public Enemy createEnemy(String type) {int x = random.nextInt(screenLength);Enemy enemy = null;switch (type) {case "Tank":enemy = new Tank(x, 0);break;case "AirPlane":enemy = new AirPlane(x, 0);break;default:throw new RuntimeException("unknown enemy type");}return enemy;}
}
这样,客户端就可以使用这个简单工厂来创建对象了,如下:
/*** 客户端*/
public class Client {public static void main(String[] args) {int screenLength = 100;new SimpleFactory(screenLength).createEnemy("Tank").show();new SimpleFactory(screenLength).createEnemy("AirPlane").show();}
}
执行结果:
分析:通过简单工厂,对对象的创建进行了封装,使客户端的代码简单、清爽。但是,如果需要增加敌人类型的话,我们就需要去修改这个简单工厂类,新增case分支,这不利于后续的代码扩展。
工厂模式
使用工厂模式,可以弥补简单工厂的缺点。我们可以创建一个工厂接口,让后续所有的敌人对象都实现这个接口,并实现其抽象方法,把对象的创建放到具体实现类中,这样后续无论新增多少种敌人类型,都只要实现这个接口即可,不需要对原有系统进行修改。如下:
(工厂接口)
/*** 敌人工厂接口*/
public interface Factory {/*** 创建敌人* * @param screenLength* @return*/Enemy createEnemy(int screenLength);
}
(飞机工厂)
import java.util.Random;/*** 飞机工厂*/
public class AirPlaneFactory implements Factory{@Overridepublic Enemy createEnemy(int screenLength) {return new AirPlane(new Random().nextInt(screenLength), 0);}
}
(坦克工厂)
import java.util.Random;/*** 坦克工厂*/
public class TankFactory implements Factory{@Overridepublic Enemy createEnemy(int screenLength) {return new Tank(new Random().nextInt(screenLength), 0);}
}
现在,如果需要新增一个Boss对象,只需要创建对应的Boss对象,及其工厂实现类即可,如下:
(Boss类)
/*** Boss*/
public class Boss extends Enemy{public Boss(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("Boss出现了,坐标是:" + x + "," + y);}
}
(Boss工厂实现类,用于创建Boss)
import java.util.Random;/*** Boss工厂*/
public class BossFactory implements Factory {@Overridepublic Enemy createEnemy(int screenLength) {// Boss出现在屏幕正中间return new Boss(screenLength / 2, 0);}
}
(客户端代码,客户端只需创建工厂对象,调用其方法即可)
/*** 客户端*/
public class Client {public static void main(String[] args) {// 屏幕宽度int screenLength = 100;// 创建坦克Factory tankFactory = new TankFactory();for (int i = 0; i < 10; i++) {tankFactory.createEnemy(screenLength).show();}// 创建飞机Factory airFactory = new AirPlaneFactory();for (int i = 0; i < 10; i++) {airFactory.createEnemy(screenLength).show();}// 创建BossFactory boosFactory = new BossFactory();boosFactory.createEnemy(screenLength).show();}
}
执行结果:
总结
本文参考《设计模式的艺术》、《秒懂设计模式》两书