动机(Motivation)
- 在软件系统中,经常面临着创建对象的工作:由于需求的变化,需要创建的对象的具体类型经常变化。
- 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?
- 可以控制对象的生产过程,对对象做一些额外操作,权限、修饰、日志等等。
模式定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:接口)。
为什么要定义创建对象的接口,而不是用户直接调用具体的对象
- 因为创建对象通常不仅仅是一个new 操作,可能是一系列赋值操作,因此需要一个抽象创建对象接口提供一个创建方法。
类图
实例
未使用工厂方法之前
- 场景
不同种类的分割器,分割器的使用者需要分割不同类型的东西,比如分割文件、视频等。 - 抽象一个分割器接口,抽象出一个稳定接口, 这样分割器就可以自由的扩展了。
public interface ISplitter {
void split();
}
- 文件分割器、视频分割器分别实现抽象的分割器接口
public class FileSplitter implements ISplitter {
@Override
public void split() {
System.out.println("File split");
}
}
public class VideoSplitter implements ISplitter {
@Override
public void split() {
System.out.println("Video split");
}
}
- 创建分割器工具,用于作为用户调用分割器的框架
public class SplitterTool {
public void split() {
// 依赖了具体的类,违反依赖倒置原则
ISplitter splitter = new FileSplitter();
splitter.split();
}
}
- 物体分割器用户使用分割器分割不同类型的物体
public class SplitterUser {
public static void main(String[] args) {
SplitterTool tool = new SplitterTool();
tool.split();
}
}
// 执行结果
// File split
- 可以看出,用户不能方便的分割不同类型的问题,因为分割器工具与具体的文件分割器绑定了,违反了依赖倒置原则。代码出现了紧耦合。
使用工厂方法模式,构造稳定的分割器工具,使代码松耦合。
- 定义一个创建对象的接口
public interface SplitterFactory {
ISplitter createSplitter();
}
- 实例化创建对象的接口,把具体的类型创建延迟到子类
public class VideoSpliiterFactory implements SplitterFactory {
@Override
public ISplitter createSplitter() {
return new VideoSplitter();
}
}
public class FileSpliiterFactory implements SplitterFactory {
@Override
public ISplitter createSplitter() {
return new FileSplitter();
}
}
- 改造分割器工具,使它成为稳定不变的框架工用户调用
public class SplitterTool {
private SplitterFactory splitterFactory;
public void setSplitterFactory(SplitterFactory factory) {
this.splitterFactory = factory;
}
public SplitterTool(SplitterFactory splitterFactory) {
this.splitterFactory = splitterFactory;
}
// 稳定不变,具体的工厂类有构造或者set方法传入
public void split() {
ISplitter splitter = splitterFactory.createSplitter();
splitter.split();
}
}
- 用户可以很方便的增加不同的分割器,需要可以方便的扩展,产品也可以方便的扩展,唯一的缺点就是类会成倍的扩展
public class SplitterUser {
public static void main(String[] args) {
SplitterTool tool = new SplitterTool(new FileSpliiterFactory());
tool.split();
tool.setSplitterFactory(new VideoSpliiterFactory());
tool.split();
}
}
- 可以看到变化点只在用户调用(用户肯定要知道需要什么,所以肯定是变化的,也是造成变化的源头),具体的工厂、具体的产品类是变化点,方便扩展,满足开闭原则;framwork和抽象的工厂、抽象的产品是不变的,framwork依赖抽象,framwork和抽象是所有设计模式的重点。
静态工厂方法
使用类的静态方法封装对象的生成,通常用来代替类的构造器,让代码更易读、易维护。
提高了类的提供者对自己提供的类的掌控力。
作为一个开发者,当我们作为调用方,使用别人提供的类时,如果使用new关键字来创建一个类实例时,如果对类不是特别熟悉,那么要一定特别慎重一一 new实在是太好用了,以致于它经常被滥用,随意的new是有很大风险的,除了可能导致性能、内存方面的问题外,也经常会使得代码结构变得混乱,难以维护。
当我们作为类的提供方时,无法控制调用者的具体行为,但是我们可以尝试使用一些方法来增大自己对类的控制力,减少调用方犯错的机会,这也是对代码更负责任的具体体现。
参考
要点总结
- Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
- Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好的解决了这种紧耦合关系。
- Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100415.html