定义
-
抽象工厂模式是一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类
-
简而言之抽象工厂是一个中心超级工厂,创建其他工厂的模式。
优点
- 单一职责原则,将产品生成代码抽取同一位置,使得代码易于维护。
- 开闭原则, 在向应用程序中引入新产品变体时, 你无需修改客户端代码。
- 可以确保同一工厂生成的产品相互匹配。
- 可以避免客户端和具体产品代码的耦合。
缺点
- 该模式需要向应用程序中引入众多接口和类, 代码可能会比之前更加复杂。
实践
举例
操作系统分为mac、win,如今需要为各个操作系统设计对应的元素UI,客户端代码无需与具体UI 类耦合,就能创建跨平台的 UI 元素,同时确保所创建的元素与指定的操作系统匹配。
思路
先创建一个操作系统工厂枚举类,再创建操作系统工厂接口,然后创建两个操作系统工厂(假设只有2个:mac、win)类来实现该接口,在这两个类中有创建对应操作系统的UI元素(如按钮、复选框)的方法,最后将两个操作系统工厂类服务存储到map去,按需调取。
代码
- 创建操作系统工厂类枚举
/**
* @Author 勤任风
* @Description 工厂类枚举
* @Date 2022/5/21 10:48
**/
@Getter
@ToString
public enum FactoryEnum {
WINDOW("win"),
MAC("mac");
private final String name;
FactoryEnum(String name) {
this.name = name;
}
}
- 创建GUI工厂接口
/**
* @Description GUI工厂接口
* @Date 2022/5/21 11:48
* @return
**/
public interface GUIFactory {
/**
* @Description 获取当前工厂的枚举
**/
FactoryEnum getFactoryEnum();
/**
* @Description 创建按钮
**/
Button createButton();
/**
* @Description 创建复选框
**/
CheckBox createCheckBox();
}
- 创建两个工厂:Mac工厂、Win工厂
/**
* @author 勤任风
* @date 2022-05-21 10:35
* @Description Mac工厂
*/
@Component
public class MacFactory implements GUIFactory {
@Override
public FactoryEnum getFactoryEnum() {
return FactoryEnum.MAC;
}
@Override
public Button createButton() {
return new MacButton();
}
@Override
public CheckBox createCheckBox() {
return new MacCheckBox();
}
}
/**
* @author 勤任风
* @date 2022-05-21 10:35
* @Description Win工厂
*/
@Component
public class WinFactory implements GUIFactory {
@Override
public FactoryEnum getFactoryEnum() {
return FactoryEnum.WINDOW;
}
@Override
public Button createButton() {
return new WinButton();
}
@Override
public CheckBox createCheckBox() {
return new WinCheckBox();
}
}
- 创建按钮接口、复选框接口
/**
* @Author 勤任风
* @Description 按钮接口
* @Date 2022/5/21 11:50
**/
public interface Button {
void paint();
}
/**
* @Author 勤任风
* @Description 复选框接口
* @Date 2022/5/21 11:50
**/
public interface CheckBox {
void paint();
}
- 创建复选框、按钮对应系统的样式实现
public class MacButton implements Button {
@Override
public void paint() {
System.out.println("画Mac风格的按钮");
}
}
public class MacCheckBox implements CheckBox {
@Override
public void paint() {
System.out.println("画Mac风格的复选框");
}
}
public class WinButton implements Button {
@Override
public void paint() {
System.out.println("画Window风格的按钮");
}
}
public class WinCheckBox implements CheckBox {
@Override
public void paint() {
System.out.println("画window风格的复选框");
}
}
- 创建工厂类的管理
该类同时实现了InitializingBean, ApplicationContextAware两个接口
/**
* @author 勤任风
* @date 2022-05-21 10:43
* @Description 工厂类的处置,包括初始化、创建
*/
@Service
public class GUIHandlerFactory implements InitializingBean,ApplicationContextAware {
private ApplicationContext applicationContext;
// 存储所有工厂类
private static final Map<String, Supplier<GUIFactory>> FACTORY_MAP = new HashMap<>();
/**
* @Description 根据工厂名称创建工厂,从FACTORY_MAP获取
**/
public GUIFactory createFactory(String name){
Supplier<GUIFactory> guiFactorySupplier = FACTORY_MAP.get(name);
if(guiFactorySupplier!=null){
return guiFactorySupplier.get();
}
throw new IllegalArgumentException("没有该工厂");
}
@Override
public void afterPropertiesSet() {
//将所有实现了GUIFactory的工厂类都初始化到FACTORY_MAP
applicationContext.getBeansOfType(GUIFactory.class)
.values()
.forEach(c -> FACTORY_MAP.put(c.getFactoryEnum().getName(), () -> c));
System.out.println("初始化完毕");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
- 测试类
@RequestMapping("/abstractFactory")
@RestController
public class AbstractFactoryTestController {
@Autowired
GUIHandlerFactory guiHandlerFactory;
@GetMapping("/create")
public String create(@RequestParam("name")String name){
GUIFactory factory = guiHandlerFactory.createFactory(name);
factory.createButton().paint();
factory.createCheckBox().paint();
System.out.println("-------------------------------------");
return "创建工厂成功:"+factory.getFactoryEnum().toString();
}
}
测试
- 输入以下地址,调用测试接口,可以看到已经成功加载了Mac工厂类,并且正确调用了对应的方法。
- 测试win:
扩展
现在实例实现了 mac、win两个工厂,如果要新增一个工厂,可以在枚举类添加一个成员,然后再新建个工厂类实现GUIFactory即可