合成模式
外观

在软件工程中,合成模式,也翻译为组成模式,是一种设计模式。合成(composite)模式描述了一组对象,按照对待相同对象类型的一个单一实例的方式处置它们。合成模式的意图是将诸多对象合成(compose)入表示部份-整体层级的树结构之中。实现合成模式使得客户能统一的处置单独对象和合成对象[1]。
结构
[编辑]
- 客户
Client
类不直接(单独的)提及Leaf
和Composite
类,Client
转而提及公共的构件Component
接口,并且统一的处置Leaf
和Composite
。 - 叶子
Leaf
类没有子对象并且直接实现Component
接口。 - 合成
Composite
类维护Component
对象(children
)的一个容器,并且将请求转发到这些children
(for each child in children: child.operation()
)。
对象图展示运行时交互:在这个例子中,客户Client
对象发送请求到树结构的顶层合成Composite
对象(具有类型 Component
) 。这个请求被沿着树结构转发到(办理于)所有的子Component
对象(Leaf
和Composite
对象)。
示例
[编辑]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.
参见
[编辑]引用
[编辑]- ^ 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.
- ^ The Composite design pattern - Structure and Collaboration. w3sDesign.com. [2017-08-12].
外部链接
[编辑]- Composite Pattern implementation in Java
- Composite pattern description from the Portland Pattern Repository
- Composite pattern in UML and in LePUS3, a formal modelling language
- Class::Delegation on CPAN
- "The End of Inheritance: Automatic Run-time Interface Building for Aggregated Objects" by Paul Baranowski
- PerfectJPattern Open Source Project, Provides componentized implementation of the Composite Pattern in Java
- [1] A persistent Java-based implementation
- Composite Design Pattern