gof23——工厂设计模式详解
一、简单工厂(静态工厂)模式
简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定要创建哪一种产品类的实例,不属于gof23.简单工厂适用于工厂类创建对象较少的场景,且客户端只要传入工厂类的参数,对于如何创建对象并不关心。
假设现在我们有一个课程场景,有一个课程接口,和java课程和python课程两个实现类
public interface ICourse {
/**
* 录制课程视频
*/
void record();
}
public class JavaCourse implements ICourse{
/**
* 录制课程视频
*/
@Override
public void record() {
System.out.println("正在录制java课程视频");
}
public class PythonCourse implements ICourse{
/**
* 录制课程视频
*/
@Override
public void record() {
System.out.println("正在录制python视频");
}
}
public static void main(String[] args){
ICourse course1=new JavaCourse();
ICourse course2=new PythonCourse();
}
当我们的课程越来越多时,客户端的依赖就会变得越来越臃肿,因此我们需要想办法把这种依赖减弱,把创建细节隐藏起来。这里使用简单工厂对代码进行优化
public class CourseFactory {
public static ICourse getCourse(String courseName){
if("java".equals(courseName)){
return new JavaCourse();
}else if("python".equals(courseName)){
return new PythonCourse();
}
return null;
}
public static void main(String[] args) {
ICourse course1=CourseFactory.getCourse("java");
ICourse course2=CourseFactory.getCourse("python");
}
}
这样客户端就不需要去了解具体课程类的创建,直接通过工厂获取。但是如果现在我们在添加新的课程之后,仍然需要修改工厂的代码逻辑,这里我们可以采用反射进行优化。
public class CourseFactory {
public static ICourse getCourse(String className){
if(null!=className&&!"".equals(className)){
try {
return (ICourse) Class.forName(className).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
}
但传入的是字符串,可控性有待提升,我们将传入值修改为限定的类对象
public class CourseFactory {
public static ICourse getCourse(Class<? extends ICourse> clazz){
if(null!=clazz){
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
return null;
}
}
简单工厂模式的缺点:工厂类的职责相对过重,不易于扩展过于复杂的产品结构
二、工厂方法模式
工厂方法模式(Factory Method Pattern)是指定义一个创建对象的接口,让实现这个接口的类来决定实例化哪个类,工厂方法模式让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关系创建细节,而且加入新的产品是符合开闭原则。
工厂方法模式主要解决产品扩展的问题。在简单工厂中,随着产品链的丰富,工厂的职责会越来越多,不利于维护。通过工厂方法模式,我们将工厂进行拆分,一种产品一个工厂
public interface ICourseFactory {
ICourse create();
}
public class JavaFactory implements ICourseFactory{
@Override
public ICourse create() {
return new JavaCourse();
}
}
public class PythonFactory implements ICourseFactory{
@Override
public ICourse create() {
return new PythonCourse();
}
}
工厂方法模式试用以下场景:
- 创建对象需要大量的重复代码
- 客户端(应用层)不依赖于类实例如何被创建、如何被实现等细节
- 一个类通过其子类来指定创建哪个对象
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
三、抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定它们的具体类。客户端(应用层)不依赖于产品类实例如何创建、如何被实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复代码。需要体哦那个一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖具体实现。
讲解抽象工厂前,我们需要了解两个概念:产品等级结构和产品族。以品牌为例,一个品牌下的所有产品属于一个产品族,一个产品的不同品牌属于一个等级结构
以课程为例,现在一个课程包括录播视频和课程笔记
public interface MyCourseFactory {
IVideo createVideo();
INote createNote();
}
public class JavaCourseFactory implements MyCourseFactory{
@Override
public IVideo createVideo() {
return new JavaVideo();
}
@Override
public INote createNote() {
return new JavaNote();
}
}
public class PythonCourseFactory implements MyCourseFactory{
@Override
public IVideo createVideo() {
return new PythonVide();
}
@Override
public INote createNote() {
return new PythonNote();
}
}
public class JavaNote implements INote{
@Override
public void edit() {
System.out.println("java笔记");
}
}
public class JavaVideo implements IVideo{
@Override
public void record() {
System.out.println("java录播视频");
}
}
public class PythonNote implements INote{
@Override
public void edit() {
System.out.println("python笔记");
}
}
public class PythonVide implements IVideo{
@Override
public void record() {
System.out.println("python录播视频");
}
}
如上代码所示,目前课程抽象工厂有java课程和python课程这两个产品族,其中java课程的笔记和python课程的笔记属于同一个产品等级结构,java课程视频和python课程视频也属于同一个产品等级结构。
抽象工厂模式相对于工厂方法模式来说,就是一个工厂能能够生产一系列相关或相互依赖的产品,可以减少工厂类的个数,但如果需要在工厂中添加新的产品则需要修改抽象工厂接口代码,不符合开闭原则,故抽象工厂模式的缺点有:
- 规定了所有可能被创建的产品结合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
- 增加了系统抽象性和理解难度
在实际开发中我们应该根据具体情况灵活使用的设计模式,并不要求所有的代码都遵循设计原则,我们要考虑人力、时间、成本、质量,不能刻意去追求完美,但要在适当的场景遵循设计原则,这体现的是一种平衡取舍,可以帮助我们设计出更加优雅的代码结构。