我是清风~,每天学习一点点,快乐成长多一点,这些都是我的日常笔记以及总结。
简单工厂
- 定义:由一个工厂对象决定创建出哪一种产品类的实例
- 类型:创建型,但不属于GOF23种设计模式
抽象工厂和工厂方法都是由简单工厂一步一步引进。
适用场景:
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心
优点
- 只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道创建细节。
工厂类含义必要的判断逻辑,可以决定在什么时候创建那个产品的实例,客户端可以免除直接创建产品对象的责任。如果我要创建一杯咖啡,简单工厂就直接返回一杯咖啡就行了
缺点
- 工厂类的职责相对过着,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则。
因为工厂类集中了产品创建逻辑,一旦出现问题,出现bug,整个系统都会受到影响。
在使用简单工厂的时候,也会增加系统种类的个数,从类的角度来说,增加了系统的复杂度,和理解难度。
一旦增加新的产品,不得不修改产品逻辑。在产品逻辑非常多的时候, 这个工厂逻辑就会过于复杂,不利于维护和扩展。 - 简单工厂无法形成基于继承的等级结构。
业务场景
例如,CSDN上面有java的视频,python视频
创建生产视频的抽象方法,假如java和python的视频生产的时候不一样
public abstract class Video {
public abstract void produce();
}
紧接java视频的实现类
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("学习Java课程视频");
}
}
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("学习Python课程视频");
}
}
使用test客户端应用层类,非常需要依赖对应的类
使用简单工厂,在这里将创建具体的过程视频移植到简单工厂里面
public class VideoFactory {
public Video getVideo(String type){
if("java".equalsIgnoreCase(type)){
return new JavaVideo();
}else if("python".equalsIgnoreCase(type)){
return new PythonVideo();
}
return null;
}
}
测试
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new VideoFactory();
Video video = videoFactory.getVideo("java");
if(video == null){
return;
}
video.produce();
}
}
输出结果
录制Java课程视频
原来test客户端直接依赖对应的javaVideo和PythonVideo,现在并不是了。
这个应用层test依赖VideoFactory,VideoFactory它来创建java视频还是python视频,具体的生产过程都在VideoFactory,test只管直接使用
源码分析–Calendar类
JDK源码:简单工厂的体现
ctrl+N 搜索 Calendar这个类
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
进到createCalendar
里面有个 if 判断跟上面的VideoFactory差不多,语言,国家,然后就会返回这个实现,否则就会返回另外一个实现,下面的又返回了一个日本的实现
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
Calendar 实现了三个接口(序列号接口、比较、克隆),下面就是继承,Calendar 类的子类。
Calendar 是一个抽象类
工厂方法
- 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类
工厂方法让类的实例化推迟到子类中进行 - 类型:创建型
使用场景:
- 创建对象需要大量重复的代码,这个时候就可以考虑工厂方法适不适用在这里。
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
- 一个类通过其子类来只定创建哪个对象。
在这个模式中,客户端也不需要知道具体产品类的类名,只需要知道所定义的工厂就可以了,具体的产品对象都由工厂来创建,客户端只需要知道我要的产品是在哪个工厂里。
在这个模式中,利用面向对象的多态性和里氏替换原则,子类对象将覆盖父类对象,从而使系统更容易扩展。
同时,注意,把创建对象的过程推迟到子类来实现,所以创建对象的任务就委托给多个工厂的子类中的某一个,客户端在使用时无需关心是哪一个工厂子类创建产品子类,需要的时候动态指定即可。
优点
- 用户只需要关心所需产品对应的工厂,无须关心创建细节
- 加入新产品符合开闭原则,提高可可扩展性
在工厂模式中,用它来创建所需要的产品,同时又隐藏了具体产品类被实例化的细节。我们只需要关心产品对应的工厂,无需关系创建细节。
缺点
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
类的个数怎么看,在添加新的产品的时候,要编写新的产品类,而且还要提高这个产品类与之对应的具体工厂类,所以类的个数会增加,系统复杂度也增加
业务场景
与简单工厂一样,CSDN上面有java的视频,python视频,大数据课程
public abstract class Video {
public abstract void produce();
}
紧接java视频的实现类
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("学习Java课程视频");
}
}
紧接 Python视频的实现类
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("学习Python课程视频");
}
}
紧接 Data视频的实现类
public class DataVideo extends Video {
@Override
public void produce() {
System.out.println("学习Data课程视频");
}
}
这里的VideoFactory改成抽象方法
在子类中不需要传了,具体调用哪个实现,全部交由子类来实现
通过定义VideoFactory这个抽象类里面的getVideo方法,就是定义了一个规范。
为什么要使用抽象类,因为 这个类有可能对于某些行为,甚至某些属性是已知的,虽然这里有可能有抽象方法,还有已知的实现,用抽象类就比较合适
那如果这里全是未知的,完全可以使用接口来定义
public abstract class VideoFactory {
public abstract Video getVideo();
}
java视频、python视频都属于一个视频等级
产品等级、产品图是对比工厂方法的 概念
工厂方法是为了解决同一等级的业务抽象问题
先创建一个java视频的工厂
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
创建一个python视频的工厂
public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}
创建大数据视频工厂
public class DataVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new DataVideo();
}
}
现在体会一下,具体产生什么样的视频,是由这个VideoFactory的子类来决定的,
而不是交由VideoFactory来决定了
VideoFactory只定义规范锲约,并不规范产生哪一种类的视频。
产生哪一类的视频完全交由子类来决定。
测试
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new PythonVideoFactory();
VideoFactory videoFactory2 = new JavaVideoFactory();
VideoFactory videoFactory3 = new DataVideoFactory();
Video video = videoFactory.getVideo();
video.produce();
}
}
现在只想学习python
输出结果
录制Python课程视频
UML类图
video下面
- data视频,python视频,java视频,她们属于同一产品等级
- data笔记,python笔记,java笔记,她们属于同一产品等级
- java的笔记,java的视频,都属于java编程,属于同一产品族
- python的笔记,python的视频,都属于python编程,属于同一产品族
抽象工厂就是解决产品族的问题
抽象的工厂VideoFactory有三个子类,java视频工厂,data视频工厂,python视频工厂
依赖关系:
java视频工厂创建javavideo,data视频工厂创建datavideo,python视频工厂创建pythonvideo
就是VideoFactory把创建具体某个视频的职责交由子类来实现了,不在负责创建具体的课程视频
要是我想增加前端视频,那么只需要扩展video子类和VideoFactory子类即可
因为是对扩展开发的,不需要修改已有的类,降低了引入风险的可能性
源码分析-Collection集合类
JDK源码
在这接口中定义的iterator,这个方法就是工厂方法
整体Collection可以想象是一个抽象工厂
/**
* @return an <tt>Iterator</tt> over the elements in this collection
*/
Iterator<E> iterator();
这其中方法的实现,就全交由子类Itr来实现了
使用不同的iterator方法得到不同的具体产品实例
我们可以认为ArrayList就是一个具体实现工厂方法
而具体的抽象产品就是iterator接口
实际生产出来的产品就是ArrayList里面的Itr这个对象
在这里填写具体的实现,同时在具体的工厂里面返回具体的产品
这个产品是iterator抽象产品的实例
看下Itr的UML类图
抽象产品具体的arraylist里面的实际产品,这个类是跟arraylist是由依赖关系的
就是arraylist依赖它,Itr作为arraylist方法的iterator方法的一个返回值,
就是说,itr类型虽然是iterator接口类型,但是他是一个具体的产品
再看下arraylist的UML类图
从这里看出arraylist实现的接口,和其他接口抽象类直接的关系
我们看arraylist方法的iterator是依赖itr对象的,
所以他们直接是依赖关系