美文网首页
组合模式

组合模式

作者: 闹鬼的金矿 | 来源:发表于2022-04-04 19:36 被阅读0次

先举一个简单的例子:比如现在有一个快递,但是这个快递可能是一个很大的包裹,在大的包裹里面可能还包含其他小包裹,小包裹里面可能是具体的物品:可能是一把牙刷,可能是一个杯子,也可能是一台电脑,也有可能是一个更小的包裹。如果现在想统计一共有多少把牙刷,把它映射到具体的软件系统中,就不得不变所有的包裹遍历一次,判断是不是牙刷,如果是包裹还要继续往里面遍历。因为整个系统里涉及的类型可能会很多,所以肯定会有很多if else 类型的判断,如果增加新的类型,就必须再增加一个if。维护起来是非常麻烦,最后可能会产生一个无比巨大的用来专门判断是某种类型的方法。

这个快递的例子是一个树状的结构,如果要优化解决需求的方法,那么它的核心是如何能更有效率的遍历节点。像这种情况使用组合模式就非常有效果了。

组合模式的UML图如下所示:

组合模式UML.png

组合模式将树形结构的节点(可能是"包裹",也可能是一个"具体的物品")抽象成了一个Component,这个Component有个execute方法用来处理所有节点共性的逻辑。Component的继承者中分了两种不同的类型,因为这两种类型也有显著不同的特点。一个是"具体的物品",通过Leaf来表示,它不能包含其他节点。另一种是Composite,它是一个集合类型,可能管理了不同的Leaf或者是更小的Composite。同时,Composite也可以被当做一个子节点被包含在其他Composite中。

在实际的例子中,Leaf可能也很多种:Leaf0,Leaf1,..., LeafN。每种Leaf的excute方法根据其特定的类型实现特定的不同逻辑。对于Composite的excute实现,其实是派发给它包含的所有Leaf进行处理了。所以对于使用者来说,Leaf和Componet本质上可能不需要区别对待的,因为它们都可以看作是Component。

总的来说,组合模式是比较好理解的。适合组合模式的场景是这种树状或者网状结构的业务模型,它提供了高效遍历节点的方法。

下面是一个使用组合模式的具体例子:能够画出各种形状的程序。

声明了抽象节点的接口,声明了一个id方法,是为了给每个节点设计唯一id,在集合处理删除元素会用到。
CompoentId的作用主要是为了统一处理id生成的逻辑,避免每个Node都需要自己生成。

protocol Component {
    func move(point: CGPoint);
    func draw();
    func id() -> String;
}

class ComponentId: Component {
    
    private let i: String
    
    init() {
        self.i = "\(Date().timeIntervalSince1970)"
    }
    
    func id() -> String {
        return self.i
    }
    
    func move(point: CGPoint){
        
    }
    
    func draw(){
        
    }
}

Leaf节点设计了Point和Circle两种类型

class Point:  ComponentId {
    
    var p: CGPoint = CGPoint(x: 0, y: 0)
    
    override func move(point: CGPoint) {
        self.p = point
    }
    
    override func draw() {
        print("p = \(self.p), draw Point")
    }

}

class Circle: ComponentId {
    var p: CGPoint = CGPoint(x: 0, y: 0)
    
    override func move(point: CGPoint) {
        self.p = point
    }
    
    override func draw() {
        print("p = \(self.p), draw Circle")
    }
}

Composite的实现:移除元素需要通过元素自己定义的唯一id进行区分,通过id找到对应的元素

class Composite: ComponentId {
    
    var children: [Component] = [Component]()
    
    override func draw() {
        for child in self.children {
            child.draw()
        }
    }
    
    override func move(point: CGPoint) {
        for child in self.children {
            child.move(point: point)
        }
    }
    
    func addChild(c: Component) {
        self.children.append(c)
    }
    
    func removeChild(c: Component) {
        if let index = self.children.firstIndex(where: { (c2) -> Bool in
            return c.id() == c2.id()
        }) {
            self.children.remove(at: index)
        }
    }
}

测试代码:

func compositeTest() {
    
    let p = Point()
    let circle = Circle()
    
    let c = Composite()
    c.addChild(c: p)
    c.move(point: CGPoint(x: 100, y: 100))
    c.draw()
    
    c.addChild(c: circle)
    c.move(point: CGPoint(x: 200, y: 200))
    c.draw()
    
    c.removeChild(c: p)
    c.move(point: CGPoint(x: 150, y: 150))
    c.draw()
}

Reference: design-patterns

相关文章

  • 设计模式:组合模式 职责链模式

    组合模式 职责链模式 组合模式 组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。 在组合模式的树形结...

  • 第4章 结构型模式-组合模式

    一、组合模式简介 二、组合模式的优缺点 三、组合模式的使用场景 、组合模式的实例

  • 组合模式(统一叶子与组合对象)

    目录 从生活场景出发,映射组合模式 组合模式的理论概念 组合模式的实现 组合模式在源码中的应用 组合 “优于” 继...

  • 组合模式

    1. 组合模式 1.1 组合模式的定义 组合模式(Composite): 又称部分-整体模式, 将对象组合成树形结...

  • 组合模式

    设计模式系列7--组合模式 《Objective-c 编程之道 iOS 设计模式解析》 - 组合模式 常见组合模式...

  • 设计模式 | 组合模式及典型应用

    本文的主要内容: 介绍组合模式 示例 组合模式总结 源码分析组合模式的典型应用java.awt中的组合模式Java...

  • 组合模式

    一、组合模式介绍 二、组合模式代码实例

  • 组合模式

    设计模式之组合模式 什么是组合模式? 组合模式允许你将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以...

  • 15、组合模式(Composite Pattern)

    1. 组合模式 1.1 简介   Composite模式,即组合模式,又叫部分整体模式。Composite模式将对...

  • 组合模式原型解析

    组合模式定义: 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象...

网友评论

      本文标题:组合模式

      本文链接:https://www.haomeiwen.com/subject/pxzcsrtx.html