设计模式[2]-工厂模式
工厂模式
1. 简单工厂模式
简单工厂模式主要包括三种角色:
- 简单工厂 : 创建具体产品
- 抽象产品 : 具体产品的父类
- 具体产品 : 简单工厂创建的对象
例子:
设计一个游戏机类(GameConsole) 作为抽象产品,然后设计具体的产品(PlanStation4,XboxOne,WiiU),最后在简单工厂中创建具体的产品。逻辑很简单。
GameConsole:
public abstract class GameConsole {
public abstract String getName();
public void play() {
powerOn();
System.out.println("正在用 " + getName() + " 玩游戏");
powerOff();
}
private void powerOn() {
System.out.println("开机 >>> ");
}
private void powerOff() {
System.out.println("关机 >>>");
}
}
PlayStation4:
public class PlayStation4 extends GameConsole {
@Override
public String getName() {
return "playStation 4";
}
}
XboxOne:
public class XboxOne extends GameConsole {
@Override
public String getName() {
return "Xbox One";
}
}
WiiU:
public class WiiU extends GameConsole {
@Override
public String getName() {
return "Wii U";
}
}
简单工厂类:GameConsoleSimpleFactory
public class GameConsoleSimpleFactory {
public GameConsole createGameConsole(String type) {
if ("Sony".equals(type)) {
return new PlayStation4();
} else if ("Microsoft".equals(type)) {
return new XboxOne();
} else if ("Nintendo".equals(type)) {
return new WiiU();
} else {
throw new RuntimeException("不支持的游戏机");
}
}
}
测试类:
@Test
void createGameConsole() {
String[] arr = new String[]{"Sony", "Microsoft", "Nintendo"};
GameConsoleSimpleFactory factory = new GameConsoleSimpleFactory();
for (String type : arr) {
GameConsole console = factory.createGameConsole(type);
console.play();
System.out.println();
}
}
输出:
开机 >>>
正在用 playStation 4 玩游戏
关机 >>>
开机 >>>
正在用 Xbox One 玩游戏
关机 >>>
开机 >>>
正在用 Wii U 玩游戏
关机 >>>
优缺点
简单工厂类工厂和产品职责区分明确,但是工厂类过于单一,如果需要引入更多的类,则需要改动工厂类,不便拓展,类型过多时,也会造成逻辑复杂。
tips:
可以在工厂方法加static关键字,无需实例化工厂类。
public static GameConsole createGameConsole(String type)
2. 工厂方法模式
工厂方法模式主要包括四种角色:
- 抽象工厂 : 只提供创建产品的接口
- 具体工厂 : 实现抽象工厂的抽象方法,完成产品的创建
- 抽象产品 : 具体产品的父类
- 具体产品 : 具体工厂所创建的对象
例子:
将简单工厂模式的例子用工厂方法模式进行实现。
抽象产品和具体产品类不变:GameConsole 类、PlayStation4类、XboxOne类、WiiU类不变。
抽象工厂:
GameConsoleFactory:
public interface GameConsoleFactory {
GameConsole createGameConsole();
}
具体工厂类:
MicrosoftGameConsoleFactory:
public class MicrosoftGameConsoleFactory implements GameConsoleFactory {
@Override
public GameConsole createGameConsole() {
return new XboxOne();
}
}
NintendoGameConsoleFactory:
public class NintendoGameConsoleFactory implements GameConsoleFactory {
@Override
public GameConsole createGameConsole() {
return new WiiU();
}
}
SonyGameConsoleFactory:
public class SonyGameConsoleFactory implements GameConsoleFactory {
@Override
public GameConsole createGameConsole() {
return new PlayStation4();
}
}
测试类
@Test
void createGameConsole() {
play(new SonyGameConsoleFactory());
play(new NintendoGameConsoleFactory());
play(new MicrosoftGameConsoleFactory());
}
private void play(GameConsoleFactory gameConsoleFactory) {
GameConsole gameConsole = gameConsoleFactory.createGameConsole();
gameConsole.play();
}
输出:
开机 >>>
正在用 playStation 4 玩游戏
关机 >>>
开机 >>>
正在用 Wii U 玩游戏
关机 >>>
开机 >>>
正在用 Xbox One 玩游戏
关机 >>>
优缺点
优点创建对象灵活,若后期有添加新的产品,不需要改旧的代码,只需要建新的具体产品类和具体的工厂类即可。
缺点也很明显,创建的类变多了,增加了系统的复杂性。
3. 抽象工厂模式
抽象工厂模式主要包括四种角色:
- 抽象工厂 : 提供创建产品的接口,但有多个创建产品的方法,可以创建多个不同等级的产品
- 具体工厂 : 实现抽象工厂的多个抽象方法,完成产品的创建
- 抽象产品 : 具体产品的父类
- 具体产品 : 具体工厂所创建的对象
抽象工厂模式是工厂方法模式的升级版。它的角色和工厂方法模式一样都是这四种。
为什么需要用到抽象工厂方法模式呢,我们可以看看上面游戏机的例子。现在如果我们还需要创建游戏机相关的游戏手柄,那么我们利用工厂方法模式来创建的话,除了建游戏手柄抽象类和具体类以外,就还需要再建游戏手柄抽象工厂还有各个品牌的游戏手柄的具体工厂。这样类创建就会过多。
所以,在使用同一个产品族的情况下,利用抽象工厂模式能够对同一产品族的不同等级的产品进行很好的创建管理。
注:同一产品族:索尼游戏机,索尼游戏手柄,这是同一产品族下的不同等级产品。
例子:
新增游戏手柄Gamepad抽象类,和具体的实现类
public abstract class Gamepad {
public abstract void getName();
}
public class MicrosoftGamepad extends Gamepad{
@Override
public void getName() {
System.out.println("微软游戏手柄");
}
}
public class SonyGamepad extends Gamepad {
@Override
public void getName() {
System.out.println("索尼游戏手柄");
}
}
public class NintendoGamepad extends Gamepad {
@Override
public void getName() {
System.out.println("任天堂游戏手柄");
}
}
原本的抽象工厂改名为游戏设备工厂GameDeviceFactory,新增创建一个游戏手柄的抽象方法
GameDeviceFactory:
public interface GameDeviceFactory {
/**
* @param
* @return "com.yt.design.abstractfactory.GameConsole"
* @description 创建游戏机对象
* @author lzf
* @date 2021/12/11 22:14
*/
GameConsole createGameConsole();
/**
* @param
* @return "com.yt.design.abstractfactory.Gamepad"
* @description 创建手柄对象
* @author lzf
* @date 2021/12/11 23:57
*/
Gamepad createGamepad();
}
具体工厂:
MicrosoftGameDeviceFactory:
public class MicrosoftGameDeviceFactory implements GameDeviceFactory {
@Override
public GameConsole createGameConsole() {
return new XboxOne();
}
@Override
public Gamepad createGamepad() {
return new MicrosoftGamepad();
}
}
MicrosoftGameDeviceFactory:
public class NintendoGameDeviceFactory implements GameDeviceFactory {
@Override
public GameConsole createGameConsole() {
return new WiiU();
}
@Override
public Gamepad createGamepad() {
return new NintendoGamepad();
}
}
SonyGameDeviceFactory:
public class SonyGameDeviceFactory implements GameDeviceFactory {
@Override
public GameConsole createGameConsole() {
return new PlayStation4();
}
@Override
public Gamepad createGamepad() {
return new SonyGamepad();
}
}
测试类:
class GameDeviceFactoryTest {
@Test
void createGameConsole() {
show(new MicrosoftGameDeviceFactory());
show(new SonyGameDeviceFactory());
show(new NintendoGameDeviceFactory());
}
private void show(GameDeviceFactory gameDeviceFactory) {
GameConsole gameConsole = gameDeviceFactory.createGameConsole();
Gamepad gamepad = gameDeviceFactory.createGamepad();
gameConsole.play();
gamepad.getName();
System.out.println();
}
}
输出:
开机 >>>
正在用 Xbox One 玩游戏
关机 >>>
微软游戏手柄
开机 >>>
正在用 playStation 4 玩游戏
关机 >>>
索尼游戏手柄
开机 >>>
正在用 Wii U 玩游戏
关机 >>>
任天堂游戏手柄
优缺点
抽象工厂模式可以在同一个抽象工厂类创建不同产品等级的对象,当增加新的产品族时也不需要修改代码,只需要创建新的具体工厂类即可。
但是,当产品族需要再加新的产品等级时,比如在增加一个游戏遥控器类,那么还是需要修改所有的抽象工厂类和具体产品类的代码的。