跳转到内容

合成模式

维基百科,自由的百科全书
合成模式的UML类图。

软件工程中,合成模式,也翻译为组成模式,是一种设计模式合成(composite)模式描述了一组对象,按照对待相同对象类型的一个单一实例的方式处置它们。合成模式的意图是将诸多对象合成(compose)入表示部份-整体层级的树结构之中。实现合成模式使得客户能统一的处置单独对象和合成对象[1]

结构

[编辑]
合成模式的样例UML类图和对象图[2]

在上面的UML类图中:

  • 客户Client类不直接(单独的)提及LeafComposite类,Client转而提及公共的构件Component接口,并且统一的处置LeafComposite
  • 叶子Leaf类没有子对象并且直接实现Component接口。
  • 合成Composite类维护Component对象(children)的一个容器,并且将请求转发到这些childrenfor each child in children: child.operation())。

对象图展示运行时交互:在这个例子中,客户Client对象发送请求到树结构的顶层合成Composite对象(具有类型 Component) 。这个请求被沿着树结构转发到(办理于)所有的子Component对象(LeafComposite对象)。

示例

[编辑]

C++

[编辑]

下面的例子是基于《设计模式》书中先于C++98的样例代码的C++23实现。

import std;

using Currency = double;
template <typename T>
using LinkedList = std::list<T>;

// declares the interface for objects in the composition.
class Equipment { // Component
private:
    std::string name;
    Currency netPrice;
protected:
    Equipment() = default;

    Equipment(const String& name): 
        name{name}, netPrice{0} {}
public:
    // implements default behavior for the interface common to all classes, as appropriate.
    [[nodiscard]]
    virtual const std::string& getName() const noexcept {
        return name;
    }

    virtual void setName(const std::string& name_) noexcept {
        name = name_;
    }

    [[nodiscard]]
    virtual Currency getNetPrice() const noexcept {
        return netPrice;
    }

    virtual void setNetPrice(Currency netPrice_) noexcept {
        netPrice = netPrice_;
    }

    // declares an interface for accessing and managing its child components.
    virtual void add(std::shared_ptr<Equipment>) = 0;
    virtual void remove(std::shared_ptr<Equipment>) = 0;
    virtual ~Equipment() = default;
};

// defines behavior for components having children.
class CompositeEquipment : public Equipment { // Composite
private:
    // stores child components.
    LinkedList<std::shared_ptr<Equipment>> equipment;
protected:
    CompositeEquipment() = default;

    CompositeEquipment(const std::string& name):
        Equipment(name), equipment{} {}
public:
    // implements child-related operations in the Component interface.
    [[nodiscard]]
    virtual Currency getNetPrice() const noexcept override {
        Currency total = Equipment::getNetPrice();
        for (const Equipment& i: equipment) {
            total += i->getNetPrice();
        }
        return total;
    }

    virtual void add(std::shared_ptr<Equipment> equipment_) override {
        equipment.push_front(equipment_.get());
    }

    virtual void remove(std::shared_ptr<Equipment> equipment_) override {
        equipment.remove(equipment_.get());
    }
};

// represents leaf objects in the composition.
class FloppyDisk : public Equipment { // Leaf
public:
    FloppyDisk(const std::string& name_):
        Equipment(name) {}

    // A leaf has no children.
    void add(std::shared_ptr<Equipment>) override {
        throw std::runtime_error("FloppyDisk::add() cannot be called!");
    }

    void remove(std::shared_ptr<Equipment>) override {
        throw std::runtime_error("FloppyDisk::remove() cannot be called!");
    }
};

class Chassis : public CompositeEquipment {
public:
    Chassis(const std::string& name): 
        CompositeEquipment(name) {}
};

int main() {
    // The smart pointers prevent memory leaks.
    std::shared_ptr<FloppyDisk> fd1 = std::make_shared<FloppyDisk>("3.5in Floppy");
    fd1->setNetPrice(19.99);
    std::println("{}: netPrice = {}", fd1->getName(), fd1->getNetPrice);

    std::shared_ptr<FloppyDisk> fd2 = std::make_shared<FloppyDisk>("5.25in Floppy");
    fd2->setNetPrice(29.99);
    std::println("{}: netPrice = {}", fd2->getName(), fd2->getNetPrice);

    std::unique_ptr<Chassis> ch = std::make_unique<Chassis>("PC Chassis");
    ch->setNetPrice(39.99);
    ch->add(fd1);
    ch->add(fd2);
    std::println("{}: netPrice = {}", ch->getName(), ch->getNetPrice);

    fd2->add(fd1);
}

程序的输出为:

3.5in Floppy: netPrice=19.99
5.25in Floppy: netPrice=29.99
PC Chassis: netPrice=89.97
terminate called after throwing an instance of 'std::runtime_error'
  what():  FloppyDisk::add

Python

[编辑]

下面是Python的例子:

from abc import ABC, abstractmethod

class Equipment(ABC):
    def __init__(self, name, netprice=0, **kwargs):
        self.name = name
        self.netprice = netprice
        for key, value in kwargs.items():
            self.__dict__[key] = value
    def get_name(self):
        return self.name
    def set_netprice(self, netprice):
        self.netprice = netprice
    def get_netprice(self):
        return self.netprice
    @abstractmethod
    def get_netprice(self): pass

class LeafEquipment(Equipment):
    def get_netprice(self):
        return self.netprice

class CompositeEquipment(Equipment):
    def __init__(self, *args, **kwargs):
        self.linked_list = []
        super().__init__(*args, **kwargs)
    def add(self, equipment):
        self.linked_list.insert(0, equipment)
    def remove(self, equipment):
        self.linked_list.remove(equipment)
    def get_netprice(self):
        total = self.netprice
        for i in self.linked_list:
            total += i.get_netprice()
        return total

class ComputerCase(CompositeEquipment): pass

class Chassis(LeafEquipment): pass

class Motherboard(CompositeEquipment): pass

class CPU(LeafEquipment): pass

class RAM(LeafEquipment): pass

class HardDisk(LeafEquipment): pass

def demo():
    cpu = CPU("x86-64 CPU", 200)
    ram = RAM("DDR4", 150)
    hd = HardDisk("SSD", 250)
    board = Motherboard("ATX board", 180)
    board.add(cpu)
    board.add(ram)
    board.add(hd)
    chassis = Chassis("Full-tower", 50)
    pc_case = ComputerCase("an assembled computer")
    pc_case.add(board)
    pc_case.add(chassis)
    print(f"The net price of {pc_case.get_name()} is {pc_case.get_netprice()}.")

其执行:

>>> demo()
The net price of an assembled computer is 830.

参见

[编辑]

引用

[编辑]
  1. ^ Gamma, Erich; Richard Helm; Ralph Johnson; John M. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. 1995: 395. ISBN 0-201-63361-2. 
  2. ^ The Composite design pattern - Structure and Collaboration. w3sDesign.com. [2017-08-12]. 

外部链接

[编辑]