说明:本文介绍设计模式中,创建型设计模式中的工厂模式;
飞机大战
创建型设计模式,关注于对象的创建,本文介绍的简单工厂和工厂模式同样也是。举一个游戏例子,如飞机大战游戏中,屏幕中敌人类型有坦克、飞机,会随机出现在画面的上方;
我们可以简单的将敌人抽象为一个抽象类,然后分别创建对应的实现类,如下:
(敌人抽象类,注意属性的修饰符,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);
}
@Override
public void show() {
System.out.println("坦克出现了,坐标是:" + x + "," + y);
}
}
(具体实现类,飞机)
/**
* 飞机
*/
public class AirPlane extends Enemy{
public AirPlane(int x, int y) {
super(x, y);
}
@Override
public void show() {
System.out.println("飞机出现了,坐标是:" + x + "," + y);
}
}
(客户端,client)
import java.util.Random;
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 屏幕宽度是100
int 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{
@Override
public Enemy createEnemy(int screenLength) {
return new AirPlane(new Random().nextInt(screenLength), 0);
}
}
(坦克工厂)
import java.util.Random;
/**
* 坦克工厂
*/
public class TankFactory implements Factory{
@Override
public 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);
}
@Override
public void show() {
System.out.println("Boss出现了,坐标是:" + x + "," + y);
}
}
(Boss工厂实现类,用于创建Boss)
import java.util.Random;
/**
* Boss工厂
*/
public class BossFactory implements Factory {
@Override
public 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();
}
// 创建Boss
Factory boosFactory = new BossFactory();
boosFactory.createEnemy(screenLength).show();
}
}
执行结果:
总结
本文参考《设计模式的艺术》、《秒懂设计模式》两书