工厂方法模式
工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型
定义Button接口
public interface Button {
void render();
void onClick(Runnable f);
}
WindowButton实现类
public class WindowsButton implements Button{
@Override
public void render() {
// 根据 WINDOW 样式渲染按钮
}
@Override
public void onClick(Runnable f) {
// 绑定本地操作系统点击事件
}
}
HTMLButton实现类
public class HTMLButton implements Button{
@Override
public void render() {
// 根据 HTMl 样式渲染按钮
}
@Override
public void onClick(Runnable f) {
// 绑定网络浏览器点击事件
}
}
声明工厂抽象类
// 创建者类声明的工厂方法必须返回一个产品类的对象。创建者的子类通常会提供该方法的实现。
abstract class Dialog {
// 创建者还可提供一些工厂方法的默认实现。
abstract Button createButton();
// 请注意,创建者的主要职责并非是创建产品。其中通常会包含一些核心业务
// 逻辑,这些逻辑依赖于由工厂方法返回的产品对象。子类可通过重写工厂方
// 法并使其返回不同类型的产品来间接修改业务逻辑。
void render() {
// 调用工厂方法创建一个产品对象。
Button okButton = createButton();
// 现在使用产品。
okButton.onClick(this::closeDialog);
okButton.render();
}
private void closeDialog() {
}
}
WebDialog实现抽象工厂
public class WebDialog extends Dialog{
@Override
Button createButton() {
return new HTMLButton();
}
}
WindowDialog实现抽象工厂
public class WindowsDialog extends Dialog{
@Override
Button createButton() {
return new WindowsButton();
}
}
public class Application {
private Dialog dialog;
// 程序根据当前配置或环境设定选择创建者的类型。
void initialize() {
// 假设readApplicationConfigFile()返回Config类型的对象,Config类包含OS属性。
Config config = readApplicationConfigFile();
if (config.getOS().equals("Windows")) {
dialog = new WindowsDialog();
} else if (config.getOS().equals("Web")) {
dialog = new WebDialog();
} else {
System.out.println(config.getOS());
}
}
// 当前客户端代码会与具体创建者的实例进行交互,但是必须通过其基本接口
// 进行。只要客户端通过基本接口与创建者进行交互,你就可将任何创建者子
// 类传递给客户端。
void main() {
this.initialize();
dialog.render();
}
// 假设的Config类
private static class Config {
private String OS;
public String getOS() {
return OS;
}
public Config() {
this.OS = System.getProperty("os.name");
}
}
// 假设的读取配置文件方法
private Config readApplicationConfigFile() {
// 读取配置文件并返回Config对象的逻辑
return new Config();
}
public static void main(String[] args) {
Application application = new Application();
application.main();
}
}
实现方式
让所有产品都遵循同一接口。 该接口必须声明对所有产品都有意义的方法。
在创建类中添加一个空的工厂方法。 该方法的返回类型必须遵循通用的产品接口。
在创建者代码中找到对于产品构造函数的所有引用。 将它们依次替换为对于工厂方法的调用, 同时将创建产品的代码移入工厂方法
如果应用中的产品类型太多, 那么为每个产品创建子类并无太大必要, 这时你也可以在子类中复用基类中的控制参数
如果代码经过上述移动后, 基础工厂方法中已经没有任何代码, 你可以将其转变为抽象类。 如果基础工厂方法中还有其他语句, 你可以将其设置为该方法的默认行为
工厂模式方法优缺点:
优点:你可以避免创建者和具体产品之间的紧密耦合
单一职责原则。 你可以将产品创建代码放在程序的单一位置, 从而使得代码更容易维护
开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型
缺点:应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂。 最好的情况是将该模式引入创建者类的现有层次结构中