首页 iOS.& Swift Books 教程设计模式

14
原型模式 由约书亚格林写

原型模式是一种允许对象复制本身的创建模式。它涉及两种类型:

  1. A 复制 声明复制方法的协议。

  2. A 原型 符合复制协议的类。

实际上有两种不同类型的副本: 浅的深的.

A shallow copy creates a new object instance, but doesn’t copy its properties. Any properties that are reference types still point to the same original objects. For example, whenever you copy a Swift Array, which is a struct and thereby happens automatically on assignment, a new array instance is created but its elements aren’t duplicated.

A deep copy creates a new object instance and duplicates each property as well. For example, if you deep copy an Array, each of its elements are copied too. Swift doesn’t provide a deep copy method on Array by default, so you’ll create one in this chapter!

你什么时候应该用它?

使用此模式可启用对象来复制本身。

For example, Foundation defines the NSCopying protocol. However, this protocol was designed for Objective-C, and unfortunately, it doesn’t work that well in Swift. You can still use it, but you’ll wind up writing more boilerplate code yourself.

Instead, you’ll implement your own Copying protocol in this chapter. You’ll learn about the prototype pattern in depth this way, and your resulting implementation will be more Swifty too!

操场例子

打开 中级agepatterns.xcWorkspace. 在里面 起动机 目录,然后打开 原型 page.

public protocol Copying: class {
  // 1
  init(_ prototype: Self)
}

extension Copying {
  // 2
  public func copy() -> Self {
    return type(of: self).init(self)
  }
}
// 1
public class Monster: Copying {

  public var health: Int
  public var level: Int

  public init(health: Int, level: Int) {
    self.health = health
    self.level = level
  }

  // 2
  public required convenience init(_ monster: Monster) {
    self.init(health: monster.health, level: monster.level)
  }
}
// 1
public class EyeballMonster: Monster {

  public var redness = 0

  // 2
  public init(health: Int, level: Int, redness: Int) {
    self.redness = redness
    super.init(health: health, level: level)
  }

  // 3
  public required convenience init(_ prototype: Monster) {
    let eyeballMonster = prototype as! EyeballMonster
    self.init(health: eyeballMonster.health,
              level: eyeballMonster.level,
              redness: eyeballMonster.redness)
  }
}
let monster = Monster(health: 700, level: 37)
let monster2 = monster.copy()
print("Watch out! That monster's level is \(monster2.level)!")
Watch out! That monster's level is 37!
let eyeball = EyeballMonster(
  health: 3002,
  level: 60,
  redness: 999)
let eyeball2 = eyeball.copy()
print("Eww! Its eyeball redness is \(eyeball2.redness)!")
Eww! Its eyeball redness is 999!
let eyeballMonster3 = EyeballMonster(monster)
@available(*, unavailable, message: "Call copy() instead")
error: 'init' is unavailable: Call copy() instead

你应该小心吗?

如图所示 操场例子,默认情况下,可以将超类实例传递给子类复制初始化程序。如果可以从超类实例完全初始化子类,则这可能不是问题。但是,如果子类添加任何新属性,则可能无法从超类实例初始化它。

教程项目

在接下来的几篇章节中,您将完成一个调用的应用程序 Mirrorpad.。这是一个绘图应用程序,允许用户创建动画镜像图纸。

// 1
public protocol Copying {
  init(_ prototype: Self)
}

extension Copying {
  public func copy() -> Self {
    return type(of: self).init(self)
  }
}

// 2
extension Array where Element: Copying {
  public func deepCopy() -> [Element] {
    return map { $0.copy() }
  }
}
public class LineShape: CAShapeLayer, Copying {
public override convenience init(layer: Any) {
  let lineShape = layer as! LineShape
  self.init(lineShape)
}

public required init(_ prototype: LineShape) {
  bezierPath = prototype.bezierPath.copy() as! UIBezierPath
  super.init(layer: prototype)

  fillColor = nil
  lineWidth = prototype.lineWidth
  path = bezierPath.cgPath
  strokeColor = prototype.strokeColor
}
public func copyLines(from source: DrawView) {
  layer.sublayers?.removeAll()
  lines = source.lines.deepCopy()
  lines.forEach { layer.addSublayer($0) }
}
mirrorDrawViews.forEach { $0.copyLines(from: inputDrawView) }
mirrorDrawViews.forEach { $0.animate() }

关键点

您了解了本章中的原型模式。以下是其关键点:

有一个技术问题?想报告一个错误吗? 您可以向官方书籍论坛中的书籍作者提出问题和报告错误 这里.

有反馈分享在线阅读体验吗? 如果您有关于UI,UX,突出显示或我们在线阅读器的其他功能的反馈,您可以将其发送到设计团队,其中表格如下所示:

© 2021 Razeware LLC

您可以免费读取,本章的部分显示为 混淆了 文本。解锁这本书,以及我们整个书籍和视频目录,带有Raywenderlich.com的专业订阅。

现在解锁

要突出或记笔记,您需要在订阅中拥有这本书或自行购买。