工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
简单工厂模式
定义
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
实例
需求:以学习课程为例
课程抽象类:
public interface ICourse {
void learn();
}
Java 课程:
public class JavaCourse implements ICourse {
@Override
public void learn() {
System.out.println("正在学习 Java ......");
}
}
Mysql 课程:
public class MysqlCourse implements ICourse {
@Override
public void learn() {
System.out.println("正在学习 Mysql ......");
}
}
课程工厂类:
public class CourseFactory {
public static final int COURSE_JAVA = 1;
public static final int COURSE_MYSQL = 2;
public ICourse getCourse(int courseType) {
switch (courseType) {
case COURSE_JAVA:
return new JavaCourse();
case COURSE_MYSQL:
return new MysqlCourse();
default:
return null;
}
}
}
学习 Java 课程:
public static void main(String[] args) {
CourseFactory factory = new CourseFactory();
ICourse course = factory.getCourse(CourseFactory.COURSE_JAVA);
course.learn();
}
优缺点
-
优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
-
缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反 GRASPR 的高内聚的责任分配原则
工厂方法模式
定义
工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现 开-闭 原则
,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。
在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
实例
以上面的课程为例,我们将工厂对象变为接口:
public interface ICourseFactory {
ICourse getCourse();
}
实现两个课程各自的工厂:
public class JavaCourseFactory implements ICourseFactory {
@Override
public ICourse getCourse() {
return new JavaCourse();
}
}
public class MysqlCourseFactory implements ICourseFactory {
@Override
public ICourse getCourse() {
return new MysqlCourse();
}
}
测试类调用:
public static void main(String[] args) {
ICourseFactory factory;
// 学习 java
factory = new JavaCourseFactory();
ICourse javaCourse = factory.getCourse();
javaCourse.learn();
// 学习 Mysql
factory = new MysqlCourseFactory();
ICourse mysqlCourse = factory.getCourse();
mysqlCourse.learn();
}
优缺点
优点:
-
屏蔽产品类。产品类的实现如何变化,调用者都不需要关心,只需关心产品的接口,只要接口保持不变,系统中的上层模块就不会发生变化。
-
典型的解耦框架。高层模块只需要知道产品的抽象类,其他的实现类都不需要关心,符合迪米特法则,符合依赖倒置原则,符合里氏替换原则。
-
多态性:客户代码可以做到与特定应用无关,适用于任何实体类。
缺点:
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到 DOM、反射等技术,增加了系统的实现难度。
抽象工厂模式
定义
为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。
实例
针对一门课程除了学习外,我们应该还要有输出笔记操作,我们来实现下笔记对象。
增加笔记接口
public interface INote {
void write();
void read();
}
具体笔记实现:
public class JavaNote implements INote {
@Override
public void write() {
System.out.println("写 Java 笔记");
}
@Override
public void read() {
System.out.println("读 Java 笔记");
}
}
public class MysqlNote implements INote {
@Override
public void write() {
System.out.println("写 Mysql 笔记");
}
@Override
public void read() {
System.out.println("读 Mysql 笔记");
}
}
修改工厂接口:
public interface ICourseFactory {
ICourse getCourse();
INote getNote();
}
工厂实现:
public class JavaCourseFactory implements ICourseFactory {
@Override
public ICourse getCourse() {
return new JavaCourse();
}
@Override
public INote getNote() {
return new JavaNote();
}
}
public class MysqlCourseFactory implements ICourseFactory {
@Override
public ICourse getCourse() {
return new MysqlCourse();
}
@Override
public INote getNote() {
return new MysqlNote();
}
}
测试类:
public static void main(String[] args) {
ICourseFactory factory;
// 学习 java
factory = new JavaCourseFactory();
ICourse javaCourse = factory.getCourse();
javaCourse.learn();
INote javaNote = factory.getNote();
javaNote.read();
// 学习 Mysql
factory = new MysqlCourseFactory();
ICourse mysqlCourse = factory.getCourse();
mysqlCourse.learn();
INote mysqlNote = factory.getNote();
mysqlNote.read();
}
优缺点
优点:
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。
缺点:
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。