likes
comments
collection
share

iOS开发常用设计模式之原型/外观模式(附代码)

作者站长头像
站长
· 阅读数 35

何为原型模式?

原型模式(Prototype Pattern)是一种创建型设计模式,它用于通过克隆(复制)现有对象来创建新对象,而无需显式地使用构造函数。原型模式允许我们创建具有相同属性的对象,同时避免了昂贵的对象创建操作。

在原型模式中,我们首先创建一个原型对象,然后通过克隆(复制)该原型对象来创建新的对象。这个克隆过程可以是浅拷贝(只复制对象的字段)或深拷贝(复制对象及其关联的对象)。通过克隆而不是创建新对象,我们可以节省创建对象的时间和资源开销。

原型模式的核心概念是原型对象,它通常实现一个克隆方法,以便在需要创建新对象时进行复制。客户端代码可以通过调用克隆方法来获取新对象,而无需了解对象的具体创建细节。

原型模式适用于以下情况:

  • 当创建对象的过程比较昂贵或复杂时,可以通过克隆已有对象来提高性能和效率。
  • 当需要创建多个具有相同属性的对象时,可以使用原型模式来避免重复的初始化过程。

总结起来,原型模式通过克隆现有对象来创建新对象,以提高性能和效率,并避免重复的初始化过程。它是一种简单而有效的对象创建方法,常用于需要频繁创建对象的场景。

如何使用原型模式?

使用原型模式的关键是定义一个原型对象并实现克隆方法。以下是使用原型模式的一般步骤:

  1. 创建一个原型对象,并确保该对象实现了克隆方法。克隆方法可以是浅拷贝(只复制对象的字段)或深拷贝(复制对象及其关联的对象)。

  2. 在需要创建新对象的地方,通过克隆原型对象来创建新对象。这通常是通过调用克隆方法来实现的。

原型模式的优缺点?

原型模式(Prototype Pattern)具有以下优点和缺点:

优点:

  1. 减少对象的创建成本:原型模式通过克隆现有对象来创建新对象,避免了昂贵的对象创建过程,提高了性能和效率。
  2. 简化对象创建过程:使用原型模式,我们可以通过复制现有对象来创建新对象,而不需要显式地使用构造函数进行初始化。这简化了对象创建的过程,尤其是当对象的创建过程较为复杂时。
  3. 动态增加和修改对象:原型模式允许在运行时动态地增加或修改对象的属性和行为。通过克隆现有对象并进行适当的修改,可以方便地创建新对象,而无需修改已有的对象结构。

缺点:

  1. 对象的克隆可能较为复杂:如果对象的内部包含其他对象或引用,那么实现对象的克隆可能比较复杂。需要确保所有相关对象也能正确地进行克隆,以避免出现意外的结果。
  2. 克隆方法的实现可能较为繁琐:在某些编程语言中,实现对象的克隆方法可能需要一些额外的工作。例如,在Java中,需要实现 Cloneable 接口并重写 clone() 方法才能进行对象的克隆。
  3. 需要正确使用深拷贝:原型模式中的克隆可以是浅拷贝(只复制对象的字段)或深拷贝(复制对象及其关联的对象)。如果需要克隆的对象包含对其他对象的引用,那么需要确保进行深拷贝,以避免共享引用导致的意外修改。

总结:原型模式通过克隆现有对象来创建新对象,提高了性能和效率,同时简化了对象的创建过程。然而,实现对象的克隆可能较为复杂,需要注意深拷贝的正确使用。在使用原型模式时,需要在性能和代码复杂性之间做出权衡,并确保正确地实现对象的克隆方法。

示例

在iOS开发中使用原型模式时,可以按照以下步骤进行实现:

  1. 创建原型协议(Prototype Protocol):定义原型模式中的克隆方法。该方法用于克隆当前对象并返回一个新的对象实例。
protocol Prototype {
    func clone() -> Prototype
}
  1. 实现具体的原型类(Concrete Prototype):实现原型协议,并在克隆方法中创建当前对象的副本。
class ConcretePrototype: Prototype {
    var property: String
    
    init(property: String) {
        self.property = property
    }
    
    func clone() -> Prototype {
        return ConcretePrototype(property: self.property)
    }
}
  1. 创建原型管理类(Prototype Manager):原型管理类负责存储和管理原型对象,并提供方法来获取和使用原型对象。
class PrototypeManager {
    private var prototypes: [String: Prototype] = [:]
    
    func registerPrototype(name: String, prototype: Prototype) {
        prototypes[name] = prototype
    }
    
    func unregisterPrototype(name: String) {
        prototypes[name] = nil
    }
    
    func clonePrototype(name: String) -> Prototype? {
        return prototypes[name]?.clone()
    }
}
  1. 在客户端代码中使用原型模式:在需要创建对象的地方,通过原型管理类获取原型对象,并使用克隆方法来创建新的对象。
let prototypeManager = PrototypeManager()

// 创建并注册原型对象
let prototypeA = ConcretePrototype(property: "Prototype A")
let prototypeB = ConcretePrototype(property: "Prototype B")

prototypeManager.registerPrototype(name: "A", prototype: prototypeA)
prototypeManager.registerPrototype(name: "B", prototype: prototypeB)

// 使用原型模式创建新对象
if let clonedA = prototypeManager.clonePrototype(name: "A") as? ConcretePrototype {
    print(clonedA.property) // 输出: Prototype A
}

if let clonedB = prototypeManager.clonePrototype(name: "B") as? ConcretePrototype {
    print(clonedB.property) // 输出: Prototype B
}

在上述示例中,首先定义了一个原型协议 Prototype,包含了一个克隆方法 clone()。然后,创建了一个具体的原型类 ConcretePrototype,它遵循了原型协议并实现了克隆方法。

接下来,创建了原型管理类 PrototypeManager,负责存储和管理原型对象。它提供了注册原型对象、注销原型对象和克隆原型对象的方法。

在客户端代码中,首先创建了一个原型管理类的实例 prototypeManager,并注册了两个原型对象。然后,通过调用原型管理类的 clonePrototype() 方法,可以获取原型对象的克隆,并创建新的对象实例。

何为外观模式?

外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口,用于简化复杂系统的访问和使用。外观模式隐藏了系统的复杂性,为客户端提供了一个简单的接口,从而使客户端与系统的各个子系统之间的交互更加简单和直接。

外观模式的核心思想是将一个系统分成多个子系统,每个子系统负责执行特定的功能。然后,通过创建一个外观类,该类封装了对这些子系统的调用,为客户端提供了一个简化的接口来访问整个系统。外观类将客户端与子系统之间的复杂交互隐藏起来,使客户端只需与外观类进行交互,而不需要直接与子系统进行通信。

外观模式的优点包括:

  1. 简化客户端代码:外观模式提供了一个简单的接口,隐藏了系统的复杂性,使客户端代码更加清晰和易于理解。

  2. 解耦客户端和子系统:外观类充当了客户端和子系统之间的中间层,使它们之间的耦合度降低。客户端只需与外观类进行交互,而无需了解和管理子系统。

  3. 提高代码的可维护性:由于外观模式将系统分成了多个子系统,每个子系统负责特定的功能,因此系统的代码更加模块化和可维护。

  4. 支持系统的演化和扩展:由于客户端与子系统之间的交互由外观类管理,因此可以在不影响客户端的情况下对系统进行修改、扩展或替换子系统。

外观模式在iOS开发中经常被使用,特别是在涉及复杂的框架或库时。通过使用外观模式,可以简化对这些复杂系统的使用,并提供一个更加友好和直观的接口供开发人员使用。

如何使用外观模式?

下面是使用外观模式的一般步骤:

  1. 定义子系统类(Subsystem Classes):将复杂系统拆分为多个子系统类,每个子系统类负责执行特定的功能。这些子系统类可以是已存在的类或者新创建的类。

  2. 创建外观类(Facade Class):外观类是客户端访问系统的入口,它提供了一个简化的接口用于访问系统的功能。外观类内部包含了对各个子系统类的实例,并将客户端的请求委派给适当的子系统类来执行。

下面是一个简单的示例,假设有一个复杂的音频播放器系统,包含了多个子系统类(例如音频解码器、音量控制器、播放列表等),我们可以使用外观模式来隐藏这些子系统的复杂性:

// 子系统类
class AudioDecoder {
    func decode(file: String) {
        print("解码音频文件: \(file)")
    }
}

class VolumeController {
    func setVolume(volume: Int) {
        print("设置音量: \(volume)")
    }
}

class Playlist {
    func loadPlaylist() {
        print("加载播放列表")
    }
}

// 外观类
class AudioPlayer {
    private let decoder: AudioDecoder
    private let volumeController: VolumeController
    private let playlist: Playlist
    
    init() {
        decoder = AudioDecoder()
        volumeController = VolumeController()
        playlist = Playlist()
    }
    
    func play(file: String) {
        decoder.decode(file: file)
        volumeController.setVolume(volume: 50)
        playlist.loadPlaylist()
        
        // 更多复杂的操作...
    }
}

在上述示例中,我们定义了三个子系统类:AudioDecoderVolumeControllerPlaylist,它们分别负责音频解码、音量控制和播放列表操作。

然后,创建了外观类AudioPlayer,它内部包含了对子系统类的实例。在play(file:)方法中,外观类调用了子系统类的方法来执行音频播放所需的操作。

使用外观模式时,客户端只需与外观类进行交互,而无需直接与子系统类进行通信。客户端可以通过外观类提供的简化接口来访问系统的功能。

let player = AudioPlayer()
player.play(file: "song.mp3")

在上述示例中,我们创建了外观类的实例player,然后通过调用外观类的play(file:)方法来启动音频播放。客户端不需要知道具体的子系统类和它们的复杂操作,而是通过外观类来访问系统的功能。

外观模式可以帮助我们隐藏复杂系统的实现细节,提供一个简化的接口供客户端使用。它简化了客户端的代码,降低了系统的耦合度,并提高了代码的可维护性和可扩展性。

外观模式的优缺点

外观模式(Facade Pattern)有以下优点:

  1. 简化客户端使用:外观模式提供了一个简化的接口,隐藏了系统的复杂性,使客户端更容易理解和使用系统。客户端只需与外观类进行交互,而不需要了解系统的内部实现细节。

  2. 解耦客户端与子系统:外观模式将客户端与子系统之间的依赖关系解耦,客户端只需与外观类进行交互,而不需要直接与多个子系统类进行通信。这样可以减少客户端与子系统之间的耦合度,提高系统的灵活性和可维护性。

  3. 提高代码的可维护性:外观模式将系统的复杂性封装在外观类中,使系统的变化对客户端的影响降到最低。当系统发生变化时,只需修改外观类而不影响客户端代码,提高了代码的可维护性。

  4. 提供了一个统一的入口:外观模式提供了一个统一的入口点,客户端通过外观类来访问系统的功能。这样可以确保客户端使用系统的正确方式,并且可以对客户端的请求进行统一的管理和控制。

外观模式也有一些缺点:

  1. 违反开闭原则:在外观模式中,如果新增或修改子系统的功能,可能需要修改外观类的代码。这违反了开闭原则,因为需要修改外观类来适应变化。但是,这种修改的影响范围相对较小,只限于外观类的代码。

  2. 可能引入性能问题:外观模式的封装特性可能导致一些性能问题。由于外观类需要处理客户端的请求,并将其委派给子系统类,可能会引入一定的性能开销。在性能敏感的情况下,需要仔细评估外观模式的使用。

  3. 可能增加系统的复杂性:虽然外观模式可以简化客户端的代码,但在某些情况下,可能会引入额外的复杂性。如果子系统之间的关系复杂,或者存在多个外观类相互依赖的情况,可能会增加系统的复杂性。

总体而言,外观模式是一种有用的设计模式,可以简化复杂系统的访问和使用。它提供了一个高层次的接口,隐藏了系统的内部复杂性,提高了系统的可维护性和灵活性。然而,在使用外观模式时需要权衡其优点和缺点,并根据具体情况进行决策。

转载自:https://juejin.cn/post/7323135762797838347
评论
请登录