设计模式系列往期文章
- 设计模式学习之策略模式
- 设计模式学习之策略模式在前端的应用
- 设计模式学习之简单工厂模式
在上一篇文章中我们学习了简单工厂模式——这是工厂模式中最简单的一种模式,通过工厂类提供的方法创建类(可以类比为产品),将对象创建的具体逻辑屏蔽了起来。在需求比较简单,产品的数量比较少的情况下,简单工厂模式已经能够满足业务需要了,但是如果当产品数量非常多的时候(如几十上百个),使用简单工厂就有些捉襟见肘了。
以下图为例,我们需要开发一个跨平台的UI工具库,该工具库至少能够在Windows应用和网页端运行,很明显同一个组件(如Button)在这两个平台的实现代码是不一样的,在这种情况下使用简单工厂模式进行实现就有些麻烦了,因为现在有两个维度:平台和组件,那么应该怎么做呢?
我们先试着将这个问题简化:如果现在不考虑跨平台应用,只支持HTML进行组件的绘制就可以,这个时候就可以使用简单工厂了,代码如下:
interface Element {
void render();
void onClick();
}
class Button implements Element {
public void render() {
System.out.println("<button>Test Button</button>");
onClick();
}
public void onClick() {
System.out.println("Click! Button says - 'Hello World!'");
}
}
class Text implements Element {
public void render() {
System.out.println("<p>Test Text</p>");
onClick();
}
public void onClick() {
System.out.println("Click! Text says - 'Hello World!'");
}
}
class ElementFactory {
public static Element createElement(String type) {
switch(type) {
case "Button":
return new Button();
case "Text":
return new Text();
default:
return null;
}
}
}
之所以可以这么写,是因为产品数量比较少并且工厂产出的数据都是同一个维度的。对于多维度的数据的时候就需要请出工厂方法模式了,对应的实现思路就如上图所示的那样:
- 将Button看做工厂生产的产品接口
- 将WindowButton和HTMLButton看做具体的产品实现类
- 将WindowDialog和WebDialog看做具体的工厂实现类,由他们负责生产出对应的产品
- 将Dialog看做工厂类的抽象接口
上面的类的实现伪代码如下:
// 创建者类声明的工厂方法必须返回一个产品类的对象。创建者的子类通常会提供
// 该方法的实现。
class Dialog is
// 创建者还可提供一些工厂方法的默认实现。
abstract method createButton():Button
// 请注意,创建者的主要职责并非是创建产品。其中通常会包含一些核心业务
// 逻辑,这些逻辑依赖于由工厂方法返回的产品对象。子类可通过重写工厂方
// 法并使其返回不同类型的产品来间接修改业务逻辑。
method render() is
// 调用工厂方法创建一个产品对象。
Button okButton = createButton()
// 现在使用产品。
okButton.onClick(closeDialog)
okButton.render()
// 具体创建者将重写工厂方法以改变其所返回的产品类型。
class WindowsDialog extends Dialog is
method createButton():Button is
return new WindowsButton()
class WebDialog extends Dialog is
method createButton():Button is
return new HTMLButton()
// 产品接口中将声明所有具体产品都必须实现的操作。
interface Button is
method render()
method onClick(f)
// 具体产品需提供产品接口的各种实现。
class WindowsButton implements Button is
method render(a, b) is
// 根据 Windows 样式渲染按钮。
method onClick(f) is
// 绑定本地操作系统点击事件。
class HTMLButton implements Button is
method render(a, b) is
// 返回一个按钮的 HTML 表述。
method onClick(f) is
// 绑定网络浏览器的点击事件。
class Application is
field dialog: Dialog
// 程序根据当前配置或环境设定选择创建者的类型。
method initialize() is
config = readApplicationConfigFile()
if (config.OS == "Windows") then
dialog = new WindowsDialog()
else if (config.OS == "Web") then
dialog = new WebDialog()
else
throw new Exception("错误!未知的操作系统。")
// 当前客户端代码会与具体创建者的实例进行交互,但是必须通过其基本接口
// 进行。只要客户端通过基本接口与创建者进行交互,你就可将任何创建者子
// 类传递给客户端。
method main() is
this.initialize()
dialog.render()