目录
1、简单工厂
需要某个产品时 通过工厂来获取对应的产品而不是在需要时直接new对象,将new对象的过程交给简单工厂。
例如:要创建一个学习视频的对象;学习视频包括Java视频,python视频等 如果直接通过new的方式获取对象,获取对象时都需要通过new方式来获取对象
这样的话调用方与提供方直接耦合,不利于维护。
这时就可以通过简单工厂来帮助调用方来获取对象,起到了调用方与提供方解耦的效果
实现简单工厂
简单工厂实现类
通过简单工厂来获取实例
查看他们的UML(类图)
通过类图可以清晰的看出所用产品的创建过程都由VidoeFactory来创建,使用产品时只需实现VidoeFactory,告诉工厂需要什么产品 由他来帮助获取即可
缺点:但是这样做有一个明显的问题 就是当有新的产品类时(如现在多了一个c语言视频)就需要修改VidoeFactory 在createVideo方法中添加一层C类型的判断
这违反了程序设计中的开闭原则(对扩展开放对修改关闭)
可以通过反射的方式从一定程度上满足开闭原则
修改VidoeFactory
public Video createVideo(Class videoClass){
Video video = null;
try {
// video = (Video) videoClass.newInstance();
video = (Video) Class.forName(videoClass.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return video;
}
通过反射可以做到不用修改工厂方法就能创建新的产品
简单工厂在jdk中的使用
Java Calendar(日历类)
Calendar的createCalendar方法通过判断调用者传入的Locale的getUnicodeLocaleType方法返回来生产具体的Calendar
2、工厂方法
产品族和产品等级
在实现工厂方法前要先理解产品族和产品等级
例如 网课中由视频和课后作业组成
Java视频和Java课后作业属于同一产品族(同属于Java的产品)
Java视频和python视频属于同一产品等级(都是视频)
再例如 美的生产冰箱空调洗衣机等,而海尔也生产冰箱空调洗衣机等
美的生产冰箱空调洗衣机属于同一产品族(同属于美的的产品);海尔生产冰箱空调洗衣机属于同一产品族(同属于海尔的产品)
美的生产冰箱;海尔生产冰箱属于同一产品等级(都是冰箱);美的生产空调;海尔生产空调属于同一产品等级(都是空调)
工厂方法是解决产品等级的 抽象工厂就是用来解决产品族的 这是工厂方法和抽象工厂最大的区别以及灵活运用的点
工厂方法的父工厂类,只定义产品的生产方式 不做具体的实现方式 具体实现由各产品工厂类负责
实现一个工厂方法
父工厂类
子工厂
JavaVideoFactory负责生产JavaVideo
public class JavaVideoFactory extends VideoFactory {
@Override
public Video createVideo() {
return new JavaVideo();
}
}
PythonVideoFactory负责生产PythonVideo
public class PythonVideoFactory extends VideoFactory {
@Override
public Video createVideo() {
return new PythonVideo();
}
}
客户端需要某个产品时直接通过该产品对应的具体工厂就可获取
例如要获取JavaVideo
public class Test {
public static void main(String[] args) {
// 想要获取JavaVideo产品只需创建一个JavaVideoFactory对象
VideoFactory videoFactory = new JavaVideoFactory();
// 由JavaVideoFactory来生产JavaVideo 不需要关注video的生产细节
Video video = videoFactory.createVideo();
String product = video.product();
System.out.println("product: "+product);
}
}
现在想要扩展一个能生产c语言的视频,只需要创建一个CVideoFactory实现VideoFactory的工厂方法即可,不需要像普通工厂那样修改工厂代码,可扩展性更强
public class CVideoFactory extends VideoFactory {
@Override
public Video createVideo() {
return new CVideo();
}
}
查看UML(类图)
可以看出父类工厂只负责产品的创建规范,而具体的创建方式由各子类工厂负责,有扩展的需求时只需要扩展对应的video和factory即可,不需要做修改
3、抽象工厂
定义:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口
无需指定它们具体的类
类型:创建型
适用场景
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现
优点
- 具体产品在应用层代码隔离,无需关心创建细节
- 将一个系列的产品族统一到一起创建
缺点
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
- 增加了系统的抽象性和理解难度
产品等级结构与产品族
图中y轴(颜色相同)为产品族,x轴(形状相同)为产品等级
例如 美的生产冰箱空调洗衣机等,而海尔也生产冰箱空调洗衣机等
美的生产冰箱空调洗衣机属于同一产品族(同属于美的的产品);海尔生产冰箱空调洗衣机属于同一产品族(同属于海尔的产品)
美的生产冰箱;海尔生产冰箱属于同一产品等级(都是冰箱);美的生产空调;海尔生产空调属于同一产品等级(都是空调)
抽象工厂就是用来解决产品族问题的
实现一个抽象工厂
抽象工厂父类提供规则
public interface CourseFactory {
Article getArticle();
Video getVideo();
}
具体子类工厂
Java产品族工厂,能生产Java的所有产品
public class JavaCourseFactory implements CourseFactory {
@Override
public Article getArticle() {
return new JavaArticle();
}
@Override
public Video getVideo() {
return new JavaVideo();
}
}
Python产品族工厂,能生产Python的所有产品
public class PythonCourseFactory implements CourseFactory {
@Override
public Article getArticle() {
return new PythonArticle();
}
@Override
public Video getVideo() {
return new PythonVideo();
}
}
客户端获取Java产品
public class Test {
public static void main(String[] args) {
CourseFactory courseFactory = new JavaCourseFactory();
Article article = courseFactory.getArticle();
Video video = courseFactory.getVideo();
System.out.println("article: "+article.produce());
System.out.println("video: "+video.product());
}
}
查看UML(类图)
可以看出如果想要扩展新的产品族 例如 现在多了一个C语言的产品只需要添加C语言的视频和笔记类以及新增C语言的产品工厂即可,对新增产品族是非常便于扩展的
但是如果要在产品族中增加新的产品等级,例如 现在课程除了需要视频和笔记外又多了一个课堂源码模块,这时就需要对所有的工厂进行修改,违背了开闭原则
抽象工厂Java中的使用
mybatis的核心SqlSessionFactory就是使用了抽象工厂
父类工厂
子类工厂
SqlSessionFactory能生产一个产品族的所种产品,通过不同的子类工厂,客户端不需注意生产的任何细节就能获取想要的产品。