引言
几乎在每个用面向对象语言开发的应用程序中,都能见到工厂方法模式的身影。它是 抽象工厂模式 的核心组成部分。通过重载抽象工厂父类中定义的工厂方法,各种具体工厂能够创建属于自己的对象。
在工厂方法模式中,生产者 本身并不一定是抽象工厂,它可以是任意类。关键在于不直接创建对象实例,而是通过工厂方法创建对象,并以抽象类型返回。这种设计使得代码对具体类的依赖降低,便于扩展和维护。
什么是工厂方法
工厂方法也称为虚拟构造器。它适用于这种情况:一个类无法渔区需要生成那个类型的对象,像让其子类来指定所生成的对象。
抽象的Product定义了工厂方法创建的对象的接口。而实际的产品ConcreteProduct实现了Product接口。Creator定义了返回Product对象的工厂方法。它也可以为工厂方法定义一个默认的实现。返回一个默认的ConcrereProduct对象。Creator的其它操作可以调用此工程方法来创建Product对象。ConcrereCreator是Creator的子类。它重载了工厂方法,以返回ConcreteProduct的实例。
工厂方法的最初定义就是专注于让子类决定创建什么对象。
什么时候使用工厂方法
工厂方法模式特别适合以下场景:
- 当类不知道需要实例化的具体对象时(例如,使用协议或基类表示的对象)。
- 需要将对象的创建逻辑与使用逻辑解耦时(例如,在网络层或数据解析层)。
- 需要支持多种对象类型,并且类型会随需求变化时。
与简单工厂模式相比,工厂方法提供了更大的灵活性;与抽象工厂模式相比,它更关注单个对象的创建逻辑而非一组对象。
通过工厂方法模式,你的代码将能够以更高的可扩展性和灵活性应对变化,为复杂应用提供强大的支持。
如何使用工厂方法
我们以实际开发中适配深色模式和浅色模式为例, 这个场景非常适合创建多个具体的工厂。每个模式都可以有自己独特的风格和组件。我们可以通过每个工厂为特定模式创建适配的UI组件。
具体代码如下:
首先是定义组件的接口(Product)。
protocol ThemeComponent {func render()
}
接着我们来定义具体的组件,他们需要遵循ThemeComponent并实现ThemeComponent中定义的方法。
class LightButton: ThemeComponent {func render() {print("Rendering a light-themed button.")}
}class DarkButton: ThemeComponent {func render() {print("Rendering a dark-themed button.")}
}class LightTextField: ThemeComponent {func render() {print("Rendering a light-themed text field.")}
}class DarkTextField: ThemeComponent {func render() {print("Rendering a dark-themed text field.")}
}
接下来我们需要定义工厂接口(Creator),来创建产品。
protocol ThemeFactory {func createButton() -> ThemeComponentfunc createTextField() -> ThemeComponent
}
最后遵循Creator来定义具体的工厂(ConcreteCreator),创建具体的产品。
class LightThemeFactory: ThemeFactory {func createButton() -> ThemeComponent {return LightButton()}func createTextField() -> ThemeComponent {return LightTextField()}
}class DarkThemeFactory: ThemeFactory {func createButton() -> ThemeComponent {return DarkButton()}func createTextField() -> ThemeComponent {return DarkTextField()}
}
在代码中使用工厂时,只需要根据主题模式来创建不同的工厂,而创建具体组件的任务交给工厂即可。
// 假设通过用户设置或系统获取主题let isDarkMode = truelet factory: ThemeFactory = isDarkMode ? DarkThemeFactory() : LightThemeFactory()// 使用工厂创建组件let button = factory.createButton()let textField = factory.createTextField()// 渲染组件button.render()textField.render()
当isDarkModel == true时:
Rendering a dark-themed button.
Rendering a dark-themed text field.
当isDarkModel == false时:
Rendering a light-themed button.
Rendering a light-themed text field.
工厂方法在实际项目中的使用
在多主题的应用中,通常我们都会使用到工厂方法,通过将对象的创建与使用解耦,来根据不同的需求灵活地生成合适的对象。
首先定义一个主题协议,里面会定义各种颜色、图片或者是UI组件,但不需要提供实现:
public protocol MWThemeProtocol {/// 主题颜色var themeColor:UIColor { get }/// 主要容器背景颜色var containerBgColor:UIColor { get }/// 次要容器背景颜色var secondaryContainerBgColor:UIColor { get }/// 主要文字颜色var primaryTextColor:UIColor { get }...
}
接下来创建一个具体的工厂来遵守该协议,并实现所有方法,返回该工厂指定样式的内容:
public class MWThemeNormalFactory: MWThemeProtocol {/// 主题颜色public var themeColor: UIColor {return UIColor.red}/// 主要容器背景颜色public var containerBgColor: UIColor {return UIColor.white}/// 次要容器背景颜色public var secondaryContainerBgColor: UIColor {return .wm_hex("#EFF1F5")}/// 主要文本颜色public var primaryTextColor: UIColor {return .wm_hex("#11111B")}/// 次要文本颗色public var secondaryTextColor: UIColor {return .wm_hex("#6C7086")}
...
}
创建另外一个工厂,也遵循该协议并实现所有方法,返回该工厂指定样式的内容:
public class MWThemeDarkFactory: MWThemeProtocol {/// 主题颜色public var themeColor: UIColor {return UIColor.red}/// 主要容器背景颜色public var containerBgColor: UIColor {return .wm_hex("#11111B")}/// 次要容器背景颜色public var secondaryContainerBgColor: UIColor {return .wm_hex("#1E1E2E")}/// 主要文本颜色public var primaryTextColor: UIColor {return .wm_hex("#FFFFFF")}/// 次要文本颗色public var secondaryTextColor: UIColor {return .wm_hex("#BCC0CC")}
...
}
一个多主题应用的主要主题系统的核心部分就构建完成了,接下来我们只需要根据不同的主题来创建不同的工厂,工厂内部会创建该主题对应的UI元素。
public class MWThemeHelper: NSObject {/// 创建主题工厂public static var themeFactory:MWThemeProtocol = MWThemeNormalFactory()/// 启动设置主题public static func setupTheme() {// 读取系统深色模式设置}/// 更新主题private static func updateTheme(themeType:MWThemeType) {switch themeType {case .light:themeFactory = MWThemeNormalFactory()case .dark:themeFactory = MWThemeDarkFactory()}}....
}
结语
在多主题的应用中,工厂方法模式显得尤为重要。通过将对象的创建与使用解耦,我们能够根据不同的需求和情境灵活地生成合适的对象,尤其是在需要支持多个界面主题时。工厂方法不仅能帮助我们维持代码的清晰和扩展性,还能有效应对不断变化的需求。最重要的是,灵活使用工厂方法,可以提高代码的可维护性和可重用性,从而打造更加高效和可靠的应用程序。在设计时,将工厂方法与不同的需求场景结合,可以让我们的应用更具适应性,且易于扩展。