简单工厂
定义:由一个工厂对象决定创建出哪一种产品类型的实例。
类型:创建型,不过简单工厂不属于23种设计模式。
适合场景:
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数对于如何创建对象(逻辑)不关心
简单工厂优缺点:
-
优点:只需要传入一个正确的参数,就可以获取你所需要的对象而无须知道其创建细节
-
缺点:工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,可扩展性比较差,违背开闭原则
下面我们举个例子来演示简单工厂:
我们有一个Video的抽象类,可以有多个类继承这个抽象类,然后实现这个抽象类种的方法,我们的应用层要根据不同的实现了这个抽象类的类,来调用其中的方法。
- 抽象类
package com.company.factory.simplefactory;
public abstract class Video {
public abstract void produce();
}
- 继承了这个抽象类的两个子类
package com.company.factory.simplefactory;
public class JavaVideo extends Video{
@Override
public void produce() {
System.out.println("学习Java视频");
}
}
package com.company.factory.simplefactory;
public class PythonVideo extends Video{
@Override
public void produce() {
System.out.println("学习Python视频");
}
}
- 应用层测试
package com.company.factory.simplefactory;
public class test {
public static void main(String[] args) {
JavaVideo javaVideo = new JavaVideo();
PythonVideo pythonVideo = new PythonVideo();
javaVideo.produce();
pythonVideo.produce();
}
}
- 简单工厂
以上的方式,我们的应用层对实现类的依赖比较大,我们想要减小应用层对具体类的一个依赖关系,可以使用工厂的方法。
package com.company.factory.simplefactory;
public class VideoFactory {
public Video getVideo(String name) {
if (name.equals("Java")) {
JavaVideo javaVideo = new JavaVideo();
return javaVideo;
}else if (name.equals("Python")) {
PythonVideo pythonVideo = new PythonVideo();
return pythonVideo;
}
return null;
}
}
package com.company.factory.simplefactory;
public class test2 {
public static void main(String[] args) {
VideoFactory videoFactory = new VideoFactory();
Video video = videoFactory.getVideo("Python");
video.produce();
}
}
缺点:工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,可扩展性比较差,违背开闭原则
使用反射创建简单工厂可以解决该问题:
package com.company.factory.simplefactory;
public class VideoFactory {
public Video getVideoReflect(Class c) {
try {
Video video = (Video) Class.forName(c.getName()).newInstance();
return video;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
package com.company.factory;
import com.company.factory.simplefactory.JavaVideo;
import com.company.factory.simplefactory.Video;
import com.company.factory.simplefactory.VideoFactory;
public class test2 {
public static void main(String[] args) {
VideoFactory videoFactory = new VideoFactory();
Video videoReflect = videoFactory.getVideoReflect(JavaVideo.class);
videoReflect.produce();
}
}
工厂方法
定义∶定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类工厂方法让类的实例化推迟到子类中进行。
类型:创建型
适用场景:
- 创建对象需要大量重复的代码
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 一个类通过其子类来指定创建哪个对象
优点:
- 用户只需要关心所需产品对应的工厂,无须关心创建细节
- 加入新产品符合开闭原则,提高可扩展性
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
我们好像就是说,将应用层中可以直接通过一个factory来创建对象给拆分了,每次创建不同的对象,都需要给他搞个工厂来创建,这样是不是麻烦了呢?是有点。但是这样好像是符合开闭原则 了,如果要新增一个对象,然后就新建一个该对象的工厂就行,不用修改原来的逻辑代码。
- 抽象工厂类
package com.company.factory.factorymethod;
public abstract class VideoFactory {
public abstract Video getVideo();
}
- 抽象工厂类的子类来进行创建对象
package com.company.factory.factorymethod;
public class JavaFactory extends VideoFactory{
@Override
public Video getVideo() {
return new JavaVideo();
}
}
package com.company.factory.factorymethod;
public class PythonFactory extends VideoFactory{
@Override
public Video getVideo() {
return new PythonVideo();
}
}
- 测试
package com.company.factory.factorymethod;
public class test2 {
public static void main(String[] args) {
JavaFactory javaFactory = new JavaFactory();
PythonFactory pythonFactory = new PythonFactory();
Video video1 = javaFactory.getVideo();
Video video2 = pythonFactory.getVideo();
video1.produce();
video2.produce();
}
}
不同的场景需要不同的使用,比如我们的课程就不会再增加了,那么我们就可以使用简单的工厂模式,减少类的个数,并且不需要担心开闭原则的问题。
抽象工厂
定义:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,无需指定它们具体的类。
定义类型:创建型
适用场景:
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现
抽象工厂优缺点:
- 优点
- 具体产品在应用层代码隔离,无须关心创建细节
- 将一个系列的产品族统一到一起创建
- 缺点
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
- 增加了系统的抽象性和理解难度
对于抽象工厂模式,可能理解起来有点抽象,主要是我们需要了解族和等级结构的概念。
族:根据上图,我们一个族就是一个产品
等级:一个产品可能分为多个部分,比如美的(可能有美的冰箱、美的空调、美的洗衣机等),或者说Java课程(java视频课程、java原代码、Java笔记等)
我们给一个族创建一个工厂,使用这个族的工厂可以创建这个族中所有等级的对象,比如用美的工厂可以创建美的空调、美的冰箱等的对象。
下面上代码:
- 等级结构
package com.company.factory.abstractfactory;
public abstract class Video {
public abstract void produce();
}
package com.company.factory.abstractfactory;
public abstract class Article {
public abstract void produce();
}
package com.company.factory.abstractfactory;
public class JavaArticle extends Article{
@Override
public void produce() {
System.out.println("java学习笔记");
}
}
package com.company.factory.abstractfactory;
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("java学习视频");
}
}
package com.company.factory.abstractfactory;
public class PythonAritcle extends Article{
@Override
public void produce() {
System.out.println("Python学习笔记");
}
}
package com.company.factory.abstractfactory;
public class PythonVideo extends Video{
@Override
public void produce() {
System.out.println("Python学习视频");
}
}
- 族工厂
package com.company.factory.abstractfactory;
public interface CourseFactory {
Video getVideo();
Article getArticle();
}
package com.company.factory.abstractfactory;
public class JavaFactory implements CourseFactory{
@Override
public Video getVideo() {
return new JavaVideo();
}
@Override
public Article getArticle() {
return new JavaArticle();
}
}
package com.company.factory.abstractfactory;
public class PythonFactory implements CourseFactory{
@Override
public Video getVideo() {
return new PythonVideo();
}
@Override
public Article getArticle() {
return new PythonAritcle();
}
}
- 测试
package com.company.factory.abstractfactory;
public class test {
public static void main(String[] args) {
JavaFactory javaFactory = new JavaFactory();
Video video = javaFactory.getVideo();
Article article = javaFactory.getArticle();
video.produce();
article.produce();
PythonFactory pythonFactory = new PythonFactory();
Video video1 = pythonFactory.getVideo();
Article article1 = pythonFactory.getArticle();
video1.produce();
video1.produce();
}
}
抽象工厂类优点就是我们需要引入新的课程时,只需要直接新创建一个工厂类就好,但是如果我们需要新增等级结构,比如给美的新增一个热水器的产品,那么我们就需要修改原代码中的东西,违背了开闭原则。
我们需要在不同的场景合理的使用上面的三种不同的工厂模式,而不是说抽象工厂一定就是最优的。