抽象工厂
意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
说明
🥝举个栗子
为了创造一个王国,我们需要有一个具有共同特征的对象。精灵王国需要精灵国王、精灵城堡和精灵军队,而兽人王国需要兽人国王、兽人城堡和兽人军队。王国中的物体之间存在依赖关系。
🥝简单的说
抽象工厂模式提供了一种方法,可以封装一组具有共同特征的单个工厂,而无需指定它们的具体实现类
🥝编程示例
首先,根据上面的例子,为王国中的对象提供一些接口和实现
/**
* 城堡接口
*/
public interface Castle {
String getDescription();
}
/**
* 国王接口
*/
public interface King {
String getDescription();
}
/**
* 军队接口
*/
public interface Army {
String getDescription();
}
// 精灵具体实现 ->
public class ElfCastle implements Castle {
static final String DESCRIPTION = "这是一个精灵的城堡!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class ElfKing implements King {
static final String DESCRIPTION = "这是一位精灵王!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class ElfArmy implements Army {
static final String DESCRIPTION = "这是一支精灵军队!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
// 兽人的具体实现也类似 -> ...
然后我们就有了王国工厂的抽象和实现。
public interface KingdomFactory {
//给王国创建一个城堡
Castle createCastle();
//给王国任命一个国王
King createKing();
//给王国创建一支军队
Army createArmy();
}
//创建精灵王国工厂的具体实现
public class ElfKingdomFactory implements KingdomFactory {
@Override
public Castle createCastle() {
return new ElfCastle();
}
@Override
public King createKing() {
return new ElfKing();
}
@Override
public Army createArmy() {
return new ElfArmy();
}
}
//创建兽人王国工厂的具体实现
public class OrcKingdomFactory implements KingdomFactory {
@Override
public Castle createCastle() {
return new OrcCastle();
}
@Override
public King createKing() {
return new OrcKing();
}
@Override
public Army createArmy() {
return new OrcArmy();
}
}
现在我们有了一个抽象工厂,它让我们可以创建一系列相关对象,即精灵王国工厂创建精灵城堡、国王和军队等。
var factory = new ElfKingdomFactory();
var castle = factory.createCastle();
var king = factory.createKing();
var army = factory.createArmy();
castle.getDescription();
king.getDescription();
army.getDescription();
程序输出
This is the elven castle!
This is the elven king!
This is the elven Army!
现在,我们可以为我们不同的王国设计工厂。在本例中,我们创建了FactoryMaker
,负责返回ElfKingdomFactory
或OrcKingdomFactory
的实例。
客户端(调用方)可以使用FactoryMake
创建所需的工厂,进而生产不同的工厂对象。
在这个例子中,我们还使用了一个枚举来参数化客户端的王国工厂的类型。
public static class FactoryMaker {
public enum KingdomType {
ELF, ORC
}
public static KingdomFactory makeFactory(KingdomType type) {
switch (type) {
case ELF:
return new ElfKingdomFactory();
case ORC:
return new OrcKingdomFactory();
default:
throw new IllegalArgumentException("KingdomType not supported.");
}
}
}
public static void main(String[] args) {
var app = new App();
LOGGER.info("开始创建精灵王国");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
LOGGER.info(app.getArmy().getDescription());
LOGGER.info(app.getCastle().getDescription());
LOGGER.info(app.getKing().getDescription());
LOGGER.info("开始创建兽人王国");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
-- similar use of the orc factory
}
类图
适用场景
-
系统应独立于其产品的创建、组成和表示方式
-
系统应配置多个产品系列中的一个
-
相关产品对象需必须要在一起使用,需要保证产品一致性时
-
您想提供产品的类库,并且只想显示它们的接口,而不是具体的实现
-
在程序运行时,来构造特定的依赖项或调用那个产品
-
在向程序中添加新产品或产品系列时,您不希望更改现有代码。
优点
- 具体产品在应用层的代码隔离,无需关系创建的细节
- 将一个系列的产品统一到一起创建
缺点
-
java中的依赖注入隐藏了服务类依赖项,这些依赖项可能会导致运行时错误在编译时就被捕获
-
虽然在创建预定义对象时非常有用,但添加新对象(扩展新产品)可能会很复杂
-
由于大量新接口和类与模式一起引入,增加了系统的抽象性和理解难度
其它教程
经典案例
- javax.xml.parsers.DocumentBuilderFactory
- javax.xml.transform.TransformerFactory
- javax.xml.xpath.XPathFactory
- javax.xml.bind.JAXBContext
- java.util.Calendar
- java.util.ResourceBundle
- java.text.NumberFormat
- java.nio.charset.Charset
- java.net.URLStreamHandlerFactory
- java.util.EnumSet
评论区