定义
抽象工厂提供了一个创建一系列相关或相互依赖对象的接口。
无需指定它们具体的类。
类型:创建型。
适用场景
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
抽象工厂-优点
- 具体产品在应用层代码隔离,无需关心创建细节。
- 将一个系列的产品族统一放到一起创建。
抽象工厂-缺点
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改工厂的接口。
- 增加了系统的抽象性和理解难度。
抽象工厂-产品等级结构和产品族
如上图所示,横坐标代表的是产品等级,例如空调、洗衣机、冰箱等,纵坐标代表的是产品族,如美的、海尔、海信等。那横着来看,第一行都是美的的产品,第二行都是海尔的产品,第三行都是海信的产品,每一行是同一品牌的不同产品。竖着来看,第一列都是空调,第二列都是冰箱,第三列都是洗衣机,每一列都是同一产品,不过品牌不同。可以简单理解为产品等级就是不同的产品,而产品族可以理解为一个工厂,生产一些列的产品。
代码示例
我们以制作课程为例,制作课程可能包括录制视频和制作手记两个产品。
抽象课程的工厂
public interface CourseFactory {
Video getVideo();
Article getArticle();
}
抽象视频产品
public abstract class Video {
public abstract void produce();
}
抽象文章产品
public abstract class Article {
public abstract void produce();
}
假如我们要制作java相关的课程,那我们只需新增java的课程工厂,
java课程工厂
public class JavaCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
@Override
public Article getArticle() {
return new JavaArticle();
}
}
同时新增具体的java视频产品和具体的java手记产品
java视频产品
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制Java课程视频");
}
}
java手记产品
public class JavaArticle extends Article {
@Override
public void produce() {
System.out.println("编写Java课程手记");
}
}
如果后期我们又新增了python的课程,添加相应的工厂和具体的产品即可
python课程工厂
public class PythonCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
@Override
public Article getArticle() {
return new PythonArticle();
}
}
python视频产品
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("录制Python课程视频");
}
}
python手记产品
public class PythonArticle extends Article {
@Override
public void produce() {
System.out.println("编写Python课程手记");
}
}
对于应用层而言,想获取某一产品族的产品,只需要知道产品族的工厂即可,而不需要关心具体的实现细节,代码如下
public class Test {
public static void main(String[] args) {
CourseFactory courseFactory = new JavaCourseFactory();
Video video = courseFactory.getVideo();
Article article = courseFactory.getArticle();
video.produce();
article.produce();
}
}
后续新增不同的产品族,只需要新增相应的工厂和产品实例即可,可以灵活的扩展,满足开闭原则。
源码解析
例如java.sql.Connection接口,里面定义了获取Statement、PreparedStatement方法,Statement、PreparedStatement是两个抽象的产品,假如我们使用了mysql的数据库连接,那获取的Statement、PreparedStatement,也都是mysql这个产品族的。
那如果我们引入的是oracle的数据库连接,那通过connection获取的Statement、PreparedStatement就属于oracle这个产品族。
总结
通过抽象工厂,定义了工厂和产品的接口契约,规范了接口的定义,更具有通用性和扩展性,使软件的架构更加清晰,但是也增加了系统的抽象性和理解难度,在日常工作中,需要按情况进行使用。