设计模式 --6组合模式

组合模式应用场景

整体和部分可以被一致性对待 比如人力资源部 财务部的管理功能可以复用于分公司的功能
可以引入一种 树状的结构 来统一管理

组合模式概念

组合模式(Composite),将对象组合成树形结构以表示“部分 - 整体” 的层次结构。组合模式是的用户对单个对象和组合对象的使用具有一致性。

组合模式结构图

在这里插入图片描述


#include <iostream>
#include <list>
using namespace std;

//组合中对象声明接口 实现所有类共有的默认接口行为
class Component {
public:
	Component(string name)
	{
		this->name = name;
	}
	virtual void Add(Component *c) {};
	virtual void Remove(Component* c) {};
	virtual void Display(int depth) {};//展示参数表示数的深度


protected:
	string name;
};


// 在组合里面表示叶子节点对象 叶节点没有子节点
class Leaf :public Component
{
public:
	Leaf(string name) :Component(name) {

	}
	void Add(Component* c) override {
		cout << "cannot add to a leaf " << endl;
	}

	void Remove(Component* c) override {
		cout << "cannot Remove from  a leaf " << endl;
	}

	void Display(int depth) override {
		string a = string(depth, '-');
		cout << a << name << endl;
	}

};

//在组合里面定义有子节点行为 用来存储子部件
class Composite : public Component
{
public:
	Composite(string name) :Component(name) {

	}
	void Add(Component *c) override {
		children.push_back(c);
	}
	void Remove(Component *c) override {
		children.remove(c);
	}

	void Display(int depth)override
	{
		cout << string(depth, '-') << name << endl;

		for (auto Com : children)
		{
			Com->Display(depth + 2);
		}
	}



private:
	list<Component*> children;
};

int main()
{
	Composite * root = new Composite("root");
	root->Add(new Leaf("Leaf A"));
	root->Add(new Leaf("Leaf B"));

	Composite* comp = new Composite("Composite X");
	comp->Add(new Leaf("Leaf XA"));
	comp->Add(new Leaf("Leaf XB"));

	root->Add(comp);

	Composite *comp2 = new Composite("Composite XY");
	comp2->Add(new Leaf("Leaf XYA"));
	comp2->Add(new Leaf("Leaf XYB"));

	comp->Add(comp2);

	root->Add(new Leaf("Leaf C"));
	Leaf * leaf = new Leaf("Leaf D");
	root->Add(leaf);
	root->Remove(leaf);
	root->Display(1);

	return 0;
}

代码运行结果能显示出 树状的组件
在这里插入图片描述

透明方式和安全方式

透明方式
在这种实现里面 Component 中声明了所有用来管理子对象的方法 对于外界来说 叶子节点和子节点没有区别 它们具有完全一样的接口 Leaf 本身不具备Add Remove方法 所以实现它是没有任何意义的
安全方式
在Component里面不去声明Add 和 Remove方法 这样子类Left不需要去实现,而是在Composite声明所有用来管理子类对象的方法 这样做就不会遇到刚才遇到的问题 但是由于不够透明 所以树枝类将不具有相同的接口 客户端的调用需要做判断

应该视情况 来决定使用哪一种方式

什么时候使用组合模式

需求中体现部分和整体层次的结构的时候 希望用户可以忽略组合对象和单个对象的不同,统一地使用组合结构中的所有对象时 ,就应该考虑使用组合模式了
TreeView 控件使用的就是组合模式

公司管理系统使用 组合模式来构架

在这里插入图片描述


#include <iostream>
#include <list>
using namespace std;

//组合中对象声明接口 实现所有类共有的默认接口行为
class Company {
public:
	Company(string name)
	{
		this->name = name;
	}
	virtual void Add(Company *c) = 0;
	virtual void Remove(Company* c) = 0;
	virtual void Display(int depth) =0 ;//展示参数表示数的深度
	virtual void LineOfDuty() =0; //履行职责


protected:
	string name;
};


// 人力资源部门
class HRDepartment :public Company
{
public:
	HRDepartment(string name) :Company(name) {

	}
	void Add(Company* c) override {
		cout << "cannot add to a leaf " << endl;
	}

	void Remove(Company* c) override {
		cout << "cannot Remove from  a leaf " << endl;
	}

	void Display(int depth) override {
		string a = string(depth, '-');
		cout << a << name << endl;
	}
	void LineOfDuty()override
	{
		cout << name<<" 员工招聘培训管理 " << endl;
	}

};

//具体公司类 实现接口 树枝节点
class ConcreteCompany : public Company
{
public:
	ConcreteCompany(string name) :Company(name) {

	}
	void Add(Company *c) override {
		children.push_back(c);
	}
	void Remove(Company *c) override {
		children.remove(c);
	}

	void Display(int depth)override
	{
		cout << string(depth, '-') << name << endl;

		for (auto Com : children)
		{
			Com->Display(depth + 2);
		}
	}
	//履行职责
	void LineOfDuty() override {
		for (auto Com : children)
		{
			Com->LineOfDuty();
		}
	}


private:
	list<Company*> children;
};

//财务部
class FinanceDepartment :public Company
{
public:
	FinanceDepartment(string name) :Company(name) {

	}
	void Add(Company* c) override {
		cout << "cannot add to a leaf " << endl;
	}

	void Remove(Company* c) override {
		cout << "cannot Remove from  a leaf " << endl;
	}

	void Display(int depth) override {
		string a = string(depth, '-');
		cout << a << name << endl;
	}
	void LineOfDuty()override
	{
		cout << name << " 公司财务收支管理 " << endl;
	}

};

int main()
{
	ConcreteCompany * root = new ConcreteCompany("北京总公司");
	root->Add(new HRDepartment("总公司人力资源"));
	root->Add(new HRDepartment("总公司财务部门"));

	ConcreteCompany* comp = new ConcreteCompany("上海华东分公司");
	comp->Add(new HRDepartment("华东分公司人力资源部"));
	comp->Add(new HRDepartment("华东分公司财务部"));

	root->Add(comp);

	ConcreteCompany *comp2 = new ConcreteCompany("南京办事处");
	comp2->Add(new HRDepartment("南京办事处人力资源部"));
	comp2->Add(new HRDepartment("南京办事处财务部"));
	comp->Add(comp2);

	ConcreteCompany* comp1 = new ConcreteCompany("杭州办事处");
	comp1->Add(new HRDepartment("杭州办事处人力资源部"));
	comp1->Add(new HRDepartment("杭州办事处财务部"));

	comp->Add(comp1);

	cout << "结构图 :" << endl;
	root->Display(1);
	cout << "职责:" << endl;
	root->LineOfDuty();

	return 0;
}

运行后的结果图
在这里插入图片描述

组合模式的好处

组合模式定义基本对象和分公司 办事处结合对象的类层次结构 基本对象可以被组合成更复杂的类型
组合对象又可以被组合 这样不断地柜下去 客户代码 任何用到基本对象的地方都可以使用组合对象

组合模式让客户可以一致的使用组合结构和单个对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值