简单工厂
1. 为什么要用简单工厂?
-
由来:从下面的案例中,我们可以从main方法中看到,如果需要 new 不同的视频实现类的对象,需要改变类名;如果不在同一包下,还需要,还要导入相应的实现类的包;能不能让应用层代码不依赖对应的类,能否把整个生产过程放到对应的类(Factory)里面?使得应用层代码不依赖具体的实现类。
-
案例
- 类图
- 代码
package com.joncy.design; //有抽象方法的类的必须是抽象类,或者接口 public abstract class Video { public abstract void produce(); }
package com.joncy.design; public class JavaVideo extends Video{ @Override public void produce() { System.out.println("生产 JAVA 视频"); } }
package com.joncy.design; public class PythonVideo extends Video{ @Override public void produce() { System.out.println("生产 Python 视频"); } }
package com.joncy.design; import org.junit.jupiter.api.Test; public class Application { /** * 这个是存在问题的,new后面的实现类会发生改变,而且要注意的是如果是在不同的包下面,import * 也会在应用类中体现这一点,能不能不依赖对应的类,这就是简单工厂要做的 */ @Test public void test1() { Video video = new JavaVideo(); video.produce(); //如果生产Python视频是需要改变new后面的实现类的 video = new PythonVideo(); video.produce(); } }
- 运行结果:
- 类图
2. 简单工厂
①不符合开闭原则
- 对 1 的改进,添加以个 VideoFactory 中间类,使得创建对象不直接依赖于实现类,而是依赖于创建类的工厂类。导包的时候,也不需要导入实现类的包,直接导入VideoFactory。举个例子,你要喝长白山的矿泉水,不需要你再找到长白山在哪里,再跑到山里面亲自拿瓶子去装。生产矿泉水的厂家帮你弄好了,你去工厂里,告诉工厂要什么牌子的水,买就行。
- 类图改进如下:
- 代码改进如下:
package com.joncy.design;
public class VideoFactory {
/**
* 这个方法如果没有被继承的需求,可以写成static静态方法
* @param type
* @return
*/
public Video getVideo(String type) {
if("java".equalsIgnoreCase(type)) {
return new JavaVideo();
}else if("python".equalsIgnoreCase(type)){
return new PythonVideo();
}
return null;
}
}
/**
* 用简单工厂,不依赖于具体的实现类,用的是VideoFactory这个中间层,依赖于这个中间层了,不再依赖于
* 具体的实现类,导包的时候,只需要导入VideoFactory
* 但是在这个类中,如果新出现了一门课程,必须添加if else 否则就不符合开闭原则,test3解决
*/
@Test
public void test2() {
VideoFactory vf = new VideoFactory();
Video v1 = vf.getVideo("java");
v1.produce();
}
运行结果:
- 缺点:不符合开闭原则,如果我再加一个JSVideo,要在VideoFactory进行修改,违反了“闭”原则。
②符合开闭原则
- 通过反射来弥补
package com.joncy.design;
public class VideoFactory {
public Video getVdo(Class<?> c) throws Exception {
Video video = null;
video = (Video)Class.forName(c.getName()).newInstance();
return video;
}
}
/**
* 这个方法解决上面开原则的问题
* @throws Exception
*/
@Test
public void test3() throws Exception {
VideoFactory vf = new VideoFactory();
Video v1 = vf.getVdo(PythonVideo.class);
v1.produce();
}
运行结果:
3. 简单工厂概念总结
定义
- 由一个工厂对象决定创建出哪一种产品类的实例。类型:创建型
适用场景
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数对于如何创建对象(逻辑)不关心
优缺点
- 优点:只需要传入一个正确的参数,就可以获取你所需要的对象,而无需知道其创建细节。只需要告诉你字符串”矿泉水”,工厂给你返回真正的矿泉水。
- 缺点:工厂类的职责相对过重,增加新产品,需要修改工厂类的判断逻辑,违背开闭原则