1.工厂方法模式
工厂方法模式(Factory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法模式让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无需关心创建细节,而且加入新的产品时也符合开闭原则。
工厂方法模式主要解决的是产品扩展问题。在简单工厂模式中,随着产品链的丰富,如果每个课程的创建逻辑有区别,则工厂的职责会变得越来越多。最后形成的臃肿结构不便于维护。根据单一职责原则,我们将职责继续划分,专人干转事。Java课程由Java工厂创建,Python课程由Python工厂创建,对工厂本身也做一个抽象。
来看代码,首先创建ICourseFactory接口:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 8:57 2020/4/11
*/
public interface ICourseFactory {
ICourse create();
}
再分别创建子工厂,JavaCourseFactory的代码如下:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 9:05 2020/4/11
*/
public class JavaCourseFactory implements ICourseFactory {
public ICourse create() {
return new JavaCourse();
}
}
PythonCourseFactory的代码如下:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 9:06 2020/4/11
*/
public class PythonCourseFactory implements ICourseFactory {
public ICourse create() {
return new PythonCourse();
}
}
调用代码:
public static void main(String[] args) {
ICourseFactory factory = new PythonCourseFactory();
ICourse course = factory.create();
course.study();
factory = new JavaCourseFactory();
course = factory.create();
course.study();
}
来看一下类结构图:
工厂方法模式适用于以下场景:
(1)创建对象需要大量重复的代码
(2)客户端(应用层)不依赖于产品类实例如何被创建、如何被实现等细节
(3)一个类通过其子类来指定创建哪个对象
工厂方法模式的缺点:
(1)类的个数过多,增加了代码编写的复杂度
(2)增加了系统的抽象性和理解难度
2.抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是指提供一个创建一系列相关或相互依赖的接口,无须指定他们的具体类。客户端(应用层)不依赖于产品类的实例如何被创建、如何被实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
如果对产品族和产品等级结构不了解的,可以通过以下链接学习:https://www.jianshu.com/p/5fb1e21c4d19
好了上代码。还是以学习为例。现在单纯学习已经无法满足我们了,我们要养成良好的学习习惯,开始记笔记和做作业。在产品等级中增加两个产品,INote笔记和IWork作业。
IWork接口:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 9:58 2020/4/11
*/
public interface IWork {
void write();
}
INote接口
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 9:57 2020/4/11
*/
public interface INote {
void edit();
}
然后创建一个抽象工厂类CourseFactory:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:02 2020/4/11
*/
public interface CourseFactory {
INote createNote();
IWork createWork();
}
接下来,创建Java的产品族Java的笔记类JavaNote
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:06 2020/4/11
*/
public class JavaNote implements INote {
public void edit() {
System.out.println("编写Java笔记");
}
}
扩展产品等级,新建Java的作业类JavaWork
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:14 2020/4/11
*/
public class JavaWork implements IWork {
public void write() {
System.out.println("完成Java作业");
}
}
创建Java产品族的具体工厂JavaCourseFactory:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:17 2020/4/11
*/
public class JavaCourseFactory implements CourseFactory {
public INote createNote() {
return new JavaNote();
}
public IWork createWork() {
return new JavaWork();
}
}
然后创建Python产品的笔记类PythonNote:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:20 2020/4/11
*/
public class PythonNote implements INote {
public void edit() {
System.out.println("编写Python笔记");
}
}
扩展产品等级,新建Python的作业类PythonWork
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:20 2020/4/11
*/
public class PythonWork implements IWork {
public void write() {
System.out.println("完成Python作业");
}
}
创建Python产品族的具体工厂PythonCourseFactory:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:25 2020/4/11
*/
public class PythonCourseFactory implements CourseFactory {
public INote createNote() {
return new PythonNote();
}
public IWork createWork() {
return new PythonWork();
}
}
来看调用代码
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:28 2020/4/11
*/
public class AfpTest {
public static void main(String[] args) {
JavaCourseFactory factory = new JavaCourseFactory();
factory.createNote().edit();
factory.createWork().write();
PythonCourseFactory factory1 = new PythonCourseFactory();
factory1.createWork().write();
factory1.createNote().edit();
}
}
上述代码完整的描述了两个产品族:Java课程和Python课程,也描述了两个产品等级作业和笔记。抽象工厂模式非常完美清晰的描述了这样一层复杂的关系。但是,如果我们要继续扩展产品等级,将比如考试也加入,那我们的代码从抽象工厂到具体工厂都要全部调整,很显然不符合开闭原则,所以抽象工厂也是有缺点的:
(1)规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
(2)增加了系统的抽象新和理解难度。
但在实际应用中,产品等级结构升级是很正常的一件事情,只要不升级的过于频繁,可以根据实际情况不符合开闭原则,毕竟一切原则的本质都只是被使用的工具。
文章参考
《Spring5核心原理》〔中〕谭勇德(Tom)