没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。如何将这些部件组装成一辆完整的汽车并返回给用户,这是生成器模式需要解决的问题。下面就一起来看看生成器模式
生成器模式
生成器模式(Builder Pattern)也叫:建造模式,是一种对象构建模式。
1、它可以将复杂对象的建造过与它的表现分离,使得同样的构建过程可以创建不同的表示。
2、Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们.用户不知道内部的具体构建细节.
参与者
Builder:抽象建造者,为创建一个Product对象的各个部件指定抽象接口。在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口,iOS中使用协议。
ConcreteBuilder:具体建造者,实现Builder的接口以构造和装配该产品的各个部件;即实现抽象builder类的所有方法,并返回一个创建好的对象。
Director:指导者,也被称导向者,构造一个使用Builder接口的对象。它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
Product:产品,表示被构造的复杂对象,包含多个部件;ConcreateBuilder创建该产品的内部表示并定义它的装配过程;包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
Swift-Demo实例
简单实现生成器模式
//被构建的产品对象的接口
class Product {
var parts: String = ""
}
//生成器接口,定义创建一个产品对象所需的各个部件的操作
//Builder模式是把复杂对象的创建和部件的创建分别开来
protocol Builder {
//创建部件
func buildPart()
//返回最后组装成品结果 (返回最后装配好的汽车)
func getProduct() -> Product
}
//指导者,指导使用生成器的接口来构建产品对象
class Director {
let concreteBuilder: Builder
init(concreteBuilder: Builder) {
self.concreteBuilder = concreteBuilder
}
//将部件part最后组成复杂对象
func construct() ->Product{
concreteBuilder.buildPart()
return concreteBuilder.getProduct()
}
}
//Builder的具体实现ConcreteBuilder,通过具体完成接口Builder来构建或装配产品的部件;
//定义并明确它所要创建的是什么具体东西;提供一个可以重新获取产品的接口:
class ConcreteBuilder: Builder{
var product = Product()
//这里是具体如何构建partA的代码
func buildPart() {
product.parts = "adding part succss!"
}
//返回最后组装成品结果
func getProduct() -> Product{
return product
}
}
使用如下:
let director = Director(concreteBuilder: ConcreteBuilder())
let product = director.construct()
print(product.parts)//adding part succss!
通俗讲解:Builder模式的理解,简单地说,就好象我要一盖房子住,可是我不知道怎么盖(简单的砌墙,层次较低),也不知道怎么样设计(建几个房间,几个门好看,层次较高),于是我需要找一帮民工,他们会砌墙,还得找个设计师,他知道怎么设计,我还要确保民工听设计师的领导,而设计师本身也不干活,光是下命令,这里砌一堵墙,这里砌一扇门,这样民工开始建设,最后,我可以向民工要房子了。在这个过程中,设计师是什么也没有,除了他在脑子里的设计和命令,所以要房子也是跟民工要,记住了!
//最终产品为房子
class Room {
var window: String //窗户
var floor: String //地板
init(window: String, floor: String) {
self.window = window
self.floor = floor
}
}
//创建者
protocol Builder{
//制作窗户
func makeWindow()
//制作地板
func makeFloor()
//房子建成
func getRoom() ->Room?
}
//设计师其实就是指导者
class Designer{
func commandOrder(builder: Builder){
builder.makeWindow()
builder.makeFloor()
}
}
//具体创建者
class MinGong: Builder {
var window: String? //窗户
var floor: String? //地板
func makeWindow() {
window = "window"
}
func makeFloor() {
floor = "floor"
}
func getRoom() -> Room?{
if window == "window" && floor == "floor" {
let room = Room(window: window!, floor: floor!)
return room
}
return nil
}
}
使用如下:
//找到民工
let minGong = MinGong()
//找到设计师
let designer = Designer()
//民工遵守设计师的命令制作房子
designer.commandOrder(builder: minGong)
//房子建成
if let room = minGong.getRoom(){
print("window: \(room.window), floor: \(room.floor)")
//window: window, floor: floor
}
KFC吃汉堡包
声明汉堡包
// MARK: - Product
public struct Hamburger {
public let meat: Meat
public let sauce: Sauces
public let toppings: Toppings
}
extension Hamburger: CustomStringConvertible {
public var description: String {
return meat.rawValue + " burger"
}
}
相关配菜
// 肉类
public enum Meat: String {
case beef
case chicken
case kitten
case tofu
}
// 酱汁
public struct Sauces: OptionSet {
public static let mayonnaise = Sauces(rawValue: 1 << 0)
public static let mustard = Sauces(rawValue: 1 << 1)
public static let ketchup = Sauces(rawValue: 1 << 2)
public static let secret = Sauces(rawValue: 1 << 3)
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
}
// 浇头
public struct Toppings: OptionSet {
public static let cheese = Toppings(rawValue: 1 << 0)
public static let lettuce = Toppings(rawValue: 1 << 1)
public static let pickles = Toppings(rawValue: 1 << 2)
public static let tomatoes = Toppings(rawValue: 1 << 3)
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
}
制作汉堡包
// MARK: - Builder
public class HambugerBuilder {
public private(set) var meat: Meat = .beef
public private(set) var sauces: Sauces = []
public private(set) var toppings: Toppings = []
private var soldOutMeats: [Meat] = [.kitten]
public func addSauces(_ sauce: Sauces) {
sauces.insert(sauce)
}
public func removeSauces(_ sauce: Sauces) {
sauces.remove(sauce)
}
public func addToppings(_ topping: Toppings) {
toppings.insert(topping)
}
public func removeToppgins(_ topping: Toppings) {
toppings.remove(topping)
}
public func setMeat(_ meat: Meat) throws {
guard isAvailable(meat) else {
throw Error.soldOut
}
self.meat = meat
}
public func isAvailable(_ meat: Meat) -> Bool {
return !soldOutMeats.contains(meat)
}
// 创建方式
public func build() -> Hamburger {
return Hamburger(meat: meat, sauce: sauces, toppings: toppings)
}
public enum Error: Swift.Error {
case soldOut
}
}
点单
// MARK: - Director
// 由员工来点单需要什么类型的汉堡包
public class Employee {
public func createCombo1() throws -> Hamburger {
let builder = HambugerBuilder()
try builder.setMeat(.beef)
builder.addSauces(.secret)
builder.addToppings([.lettuce, .tomatoes, .pickles])
return builder.build()
}
public func createKittenSpecial() throws -> Hamburger {
let builder = HambugerBuilder()
try builder.setMeat(.kitten)
builder.addSauces(.mustard)
builder.addToppings([.lettuce, .tomatoes])
return builder.build()
}
}
使用
// MARK: - Example
let burgerFipper = Employee()
if let combo1 = try? burgerFipper.createCombo1() {
print(combo1.description)
}
if let kittenBurger = try? burgerFipper.createKittenSpecial() {
print(kittenBurger.description)
} else {
print("Sorry, no kitten burgers here...")
}
iOS中的使用场景
1、使用builder创建对象
protocol ThemeProtocol {
var backgroundColor: UIColor? { get }
var textColor: UIColor? { get }
}
class Theme: ThemeProtocol {
var backgroundColor: UIColor?
var textColor: UIColor?
typealias buildThemeClosure = (Theme) -> Void
init(build: buildThemeClosure) {
build(self)
}
}
let darkTheme = Theme(build: {
$0.backgroundColor = UIColor.black
$0.textColor = UIColor.white
})
let lightTheme = Theme(build: {
$0.backgroundColor = UIColor.white
$0.textColor = UIColor.black
})
什么时候使用
1:需要创建涉及各种部件的复杂对象,即需要一系列创建的步骤
2:当构造过程需要以不同的方式构建对象
3:相同的方法,不同的执行顺序,产生不同的事件结果
模式优点
1:松散耦合
生成器模式可以用同一个构建算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离。生成器模式正是把产品构建的过程独立出来,使它和具体产品的表现分松散耦合,从而使得构建算法可以复用,而具体产品表现也可以很灵活地、方便地展和切换。
2:可以很容易的改变产品的内部表示
在生成器模式中,由于Builder对象只是提供接口给Director使用,那么具体部件创建和装配方式是被Builder接口隐藏了的,Director并不知道这些具体的实现细节。这样一来,要想改变产品的内部表示,只需要切换Builder接口的具体实现即可,不用管Director,因此变得很容易。
3:更好的复用性
生成器模式很好的实现构建算法和具体产品实现的分离。这样一来,使得构建产品的算法可以复用。同样的道理,具体产品的实现也可以复用,同一个产品的实现,可以配合不同的构建算法使用。
模式缺点
1:建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
2:如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。
相关模式对比
抽象工厂模式与生成器相似,因为它也可以创建复杂对象。主要的区别是生成器模式着重于一步步构造一个复杂对象。而抽象工厂模式着重于多个系列的产品对象(简单的或是复杂的)。生成器在最后的一步返回产品,而对于抽象工厂来说,产品是立即返回的.
参考:
本文通过实例讲解了Swift中生成器模式的运用,通过KFC汉堡包的例子,展示了如何利用Builder创建对象,以及相同的建造方法但执行顺序不同带来的不同结果。
431

被折叠的 条评论
为什么被折叠?



