前言:
抽象工厂模式是一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类。
--注意体会工厂方法与抽象公共的比较,工厂方法易于对产品的扩展,而抽象工厂易于对系列产品的额扩展:如生产车,生产飞行,生产坦克等就用工厂方法合适;如果造不同的车,车由不同的部件组成,对部件的扩展抽象工厂就合适。
目录
一、结构
尽管具体工厂会对具体产品进行初始化, 其构建方法签名必须返回相应的抽象产品。 这样, 使用工厂类的客户端代码就不会与工厂创建的特定产品变体耦合。 客户端 (Client) 只需通过抽象接口调用工厂和产品对象, 就能与任何具体工厂/产品变体交互。
二、代码实现
应用不同的框架将md文档转换为html文档、word文档
/**
* @Description: html文档产品
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public interface HtmlDocument {
/**
* 生成html文档
*
* @return
*/
String toHtml();
/**
* 保存信息
*
* @param path 路径
* @throws IOException
*/
void save(Path path) throws IOException;
}
/**
* @Description: word文档产品
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public interface WordDocument {
void save(Path path) throws IOException;
}
/**
* @Description: Fast生成 HtmlDocument
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public class FastHtmlDocument implements HtmlDocument {
public FastHtmlDocument(String md) {
}
/**
* 打印html信息
*
* @return
*/
@Override
public String toHtml() {
return "html";
}
/**
* 保存信息
*
* @param path 路径
* @throws IOException
*/
@Override
public void save(Path path) throws IOException {
System.out.println(path);
}
}
/**
* @Description: Fast生成 WordDocument
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public class FastWordDocument implements WordDocument {
/**
* 保存信息
*
* @param path 路径
* @throws IOException
*/
@Override
public void save(Path path) throws IOException {
System.out.println(path);
}
}
/**
* @Description: Good生成 HtmlDocument
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public class GoodHtmlDocument implements HtmlDocument {
/**
* 打印html信息
*
* @return
*/
@Override
public String toHtml() {
return "GoodHtml";
}
/**
* 保存信息
*
* @param path 路径
* @throws IOException
*/
@Override
public void save(Path path) throws IOException {
System.out.println(path);
}
}
/**
* @Description: Good生成 WordDocument
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public class GoodWordDocument implements WordDocument{
@Override
public void save(Path path) throws IOException {
System.out.println(path);
}
}
/**
* @Description: 抽象工厂
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public interface AbstractFactory {
/**
* 创建Html文档
*/
HtmlDocument createHtml(String md);
/**
* 创建Word文档
*
* @param md
* @return
*/
WordDocument createWord(String md);
/**
* 获取工厂实体
*
* @param name 工厂名
* @return 实际工厂
*/
static AbstractFactory createFactory(String name) {
if (name.equalsIgnoreCase("fast")) {
return new FastFactory();
} else if (name.equalsIgnoreCase("good")) {
return new GoodFactory();
} else {
throw new IllegalArgumentException("Invalid factory name");
}
}
}
/**
* @Description: FastDoc Soft必须提供一个实际的工厂来生产这两种产品
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public class FastFactory implements AbstractFactory {
/**
* 创建Html文档
*
* @param md
*/
@Override
public HtmlDocument createHtml(String md) {
System.out.println(md);
return new FastHtmlDocument(md);
}
/**
* 创建Word文档
*
* @param md
* @return
*/
@Override
public WordDocument createWord(String md) {
System.out.println(md);
return new FastWordDocument();
}
}
/**
* @Description: Good必须提供一个实际的工厂来生产这两种产品
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public class GoodFactory implements AbstractFactory{
/**
* 创建Html文档
*
* @param md
*/
@Override
public HtmlDocument createHtml(String md) {
return new GoodHtmlDocument();
}
/**
* 创建Word文档
*
* @param md
* @return
*/
@Override
public WordDocument createWord(String md) {
return new GoodWordDocument();
}
}
/**
* @Description: 客户端测试
*
* @Author HJW
* @Date 2021/4/6
* @Version V1.0
**/
public class Client {
public static void main(String[] args) throws IOException {
// 创建AbstractFactory,实际类型是FastFactory:
AbstractFactory factory = AbstractFactory.createFactory("fast");
// 生成Html文档:
HtmlDocument html = factory.createHtml("#Hello\nHello, world!");
html.save(Paths.get(".", "fast.html"));
// 生成Word文档:
WordDocument word = factory.createWord("#Hello\nHello, world!");
word.save(Paths.get(".", "fast.doc"));
}
}
三、在JDK中的应用
四、应用场景
- 如果代码需要与多个不同系列的相关产品交互, 但是由于无法提前获取相关信息, 或者出于对未来扩展性的考虑, 你不希望代码基于产品的具体类进行构建, 在这种情况下, 你可以使用抽象工厂。
抽象工厂提供了一个接口, 可用于创建每个系列产品的对象。 只要代码通过该接口创建对象, 那么你就不会生成与应用程序已生成的产品类型不一致的产品。
- 如果你有一个基于一组抽象方法的类, 且其主要功能因此变得不明确, 那么在这种情况下可以考虑使用抽象工厂模式。
在设计良好的程序中, 每个类仅负责一件事。 如果一个类与多种类型产品交互, 就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。
五、抽象工厂模式优缺点
- 确保同一工厂生成的产品相互匹配。
- 避免客户端和具体产品代码的耦合。
- 单一职责原则。 将产品生成代码抽取到同一位置, 使得代码易于维护。
- 开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码。
xxx 由于采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂。
六、与其他模式的关系
- 在许多设计工作的初期都会使用工厂方法模式 (较为简单, 而且可以更方便地通过子类进行定制), 随后演化为使用抽象工厂模式、 原型模式或生成器模式 (更灵活但更加复杂)。
- 生成器重点关注如何分步生成复杂对象。 抽象工厂专门用于生产一系列相关对象。 抽象工厂会马上返回产品, 生成器则允许你在获取产品前执行一些额外构造步骤。
- 抽象工厂模式通常基于一组工厂方法, 但你也可以使用原型模式来生成这些类的方法。
- 当只需对客户端代码隐藏子系统创建对象的方式时, 你可以使用抽象工厂来代替外观模式。
- 你可以将抽象工厂和桥接模式搭配使用。 如果由桥接定义的抽象只能与特定实现合作, 这一模式搭配就非常有用。 在这种情况下, 抽象工厂可以对这些关系进行封装, 并且对客户端代码隐藏其复杂性。
- 抽象工厂、 生成器和原型都可以用单例模式来实现。