21种设计模式

这个设计模式系列的文章

对象创建模式 

  • 工厂
  • 抽象工厂
  • 单例
  • 原型
  • 生成器
  • 适配器
  • 桥接
  • 中介者
  • 观察者
  • 组合
  • 迭代器
  • 访问者
  • 装饰
  • 责任链
  • 模版
  • 策略
  • 命令
  • 享元
  • 代理
  • 备忘录
  • 总结篇:MVC
  • 进阶篇:MVVM

设计模式是为了解决一类问题而出现的,要深刻理解某个模式的应用场景,优点,缺点。千万不要为了使用而实用,那样很可能写出不伦不类的东西。


何为原型?

原型可以理解为模版,在创建新的对象的时候,按照模板的方式来复制。这样避免了重新创造轮子。 
简单理解就是:创建第一个模板对象,然后通过复制模板来创建新的对象,还记得UITableviewCell的Deque方法吗?这其实就是一个“原型”,


解决什么问题?

  • 解决了每次创建新的对象,都需要alloc init,这样就造成了代码要直接访问具体的类,也就增加了代码的耦合度。
  • 避免创建工厂类的子类(例如抽象工厂模式)
  • 通过copy能够保存对象当时的状态

什么时候使用原型模式?

  • 需要创建的对象不依赖于具体的类型以及创建方式
  • 具体实例化的对象类型是在运行期决定的
  • 不同类型之间的差异紧紧是状态的组合
  • 类型创建不容易,例如类型有复杂的嵌套

原型模式的UML图


实现原理

  • Swift/Objective C并不支持抽象基或者抽象方法。但是可以使用协议类似定义一个抽象的“基类”,定义通用的属性,方法,以及复制方法。
  • 具体的类负责实现复制方法,以及公用的方法。
  • 通过抽象基类的接口创建对象

Swift 2.1例子

例子是要存储复杂的嵌套数据结构

假设我有一个绘图类LeoDrawer,那么这个Drawer必然要保存每一步后操作的结果,这样我能够进行redo和undo(可以用NSUndoManager,这里只是举例)。类似这种快照就是原型模式的典型场景 
定义原型

protocol Shape{
    var location:CGPoint{get set}
    func draw()
    func clone()->Shape
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

具体的类

class RoundShape: Shape {
    var location:CGPoint
    init(location:CGPoint){
        self.location = location
    }
    func draw() {

    }
    func clone() -> Shape {
        let shape = RoundShape(location: self.location)
        return shape
    }
}
class RectShape:Shape {
    var location:CGPoint
    init(location:CGPoint){
        self.location = location
    }
    func draw() {

    }
    func clone() -> Shape {
        let shape = RectShape(location: self.location)
        return shape
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

客户端

class LeoDrawer{
    var shapes:[Shape]?
}
let drawer = LeoDrawer()
drawer.shapes = [RoundShape(location: CGPointMake(1, 1)),RectShape(location: CGPointMake(10, 10))]

let shapesSnapshot = drawer.shapes?.map({ (shape) -> Shape in
    return shape.clone()
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

优点

在扩展的时候,子类遵循原型的协议,很容易的扩展。并且,客户端代码不需要任何修改

 

posted @ 2016-11-08 23:39  象棋中的象棋  阅读(1107)  评论(0编辑  收藏  举报