前言
结构模式可以让我们把很多小的东西通过结构模式组合起来成为一个大的结构,但是又不影响各自的独立性,尽可能减少各组件之间的耦合。
Adapter Class/Object(适配器)
GOOD:双方都不适合修改的时候,可以考虑使用适配器模式,一般发生在代码的维护阶段。
adapter.h
#ifndef CLION_TEST_ADAPTER_H
#define CLION_TEST_ADAPTER_H
#include <iostream>
#include <string>
#include <utility>
using namespace std;
// 球员
class Player {
protected:
string name;
public:
explicit Player(string strName) { name = std::move(strName); }
virtual void Attack() = 0;
virtual void Defense() = 0;
};
// 前锋
class Forwards : public Player {
public:
explicit Forwards(string strName) : Player(std::move(strName)) {}
void Attack() final {
cout << name << "前锋进攻" << endl;
}
void Defense() final {
cout << name << "前锋防守" << endl;
}
};
// 中锋
class Center : public Player {
public:
explicit Center(string strName) : Player(std::move(strName)) {}
void Attack() final {
cout << name << "中场进攻" << endl;
}
void Defense() final {
cout << name << "中场防守" << endl;
}
};
// 后卫
class Guards : public Player {
public:
Guards(string name) : Player(name) {}
void Attack() final {
cout << name << "后卫进攻" << endl;
}
void Defense() final {
cout << name << "后卫防守" << endl;
}
};
// Adaptee,此处为外籍中锋,它的接口和Target的接口不一样,需要翻译来帮忙转换
class ForeignPlayerCenter {
private:
string name;
public:
void setName(string name) {
this->name = name;
}
string getName() const { return name; }
void ForeignAttack() {
cout << name << "外籍中锋进攻" << endl;
}
void ForeignDefense() {
cout << name << "外籍中锋防守" << endl;
}
};
// 为中场翻译
class TransLater : public Player {
private:
ForeignPlayerCenter *wjzf;
public:
explicit TransLater(const string &strName) : Player(strName) {
wjzf = new ForeignPlayerCenter;
wjzf->setName(name);
}
~TransLater() {
delete wjzf;
}
void Attack() {
wjzf->ForeignAttack();
}
void Defense() {
wjzf->ForeignDefense();
}
};
#endif //CLION_TEST_ADAPTER_H
main.cpp
int main()
{
system("chcp 65001");
Player *b = new Forwards("巴蒂尔");
b->Attack();
Player *m = new Guards("麦克格雷迪");;
m->Attack();
// 翻译告诉姚明,教练让你既要进攻,又有防守
Player* ym = new TransLater("姚明");
ym->Attack();
ym->Defense();
return 0;
}
Bridge(桥接)
Composite(组合)
递归构建树状的组合结构。
需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式。
应用:自定义控件,也就是把一些基本的控件组合起来,通过编程写成一个定制的控件,比如用两个文本框和一个按钮就可以写一下自定义的登录框控件,实际上,所有的Web控件的基类都是System.Web.UI.Contrrol,而Control基类中就有Add和Remove方法,这就是典型的组合模式的应用。
Component.h
#ifndef COMPONENT_H
#define COMPONENT_H
class Component {
public:
Component();
virtual ~Component();
virtual void operation() = 0;
virtual void add(const Component&);
virtual void remove(const Component&);
virtual Component* getChild(int);
};
#endif //COMPONENT_H
Component.cpp
#include "Component.h"
Component::Component() {
}
Component::~Component() {
}
void Component::add(const Component &){
}
void Component::remove(const Component &) {
}
Component *Component::getChild(int) {
return nullptr;
}
Composite.h
#ifndef COMPOSITE_H
#define COMPOSITE_H
#include "Component.h"
#include <vector>
using namespace std;
class Composite: public Component {
public:
Composite();
~Composite();
void operation();
void add(Component* component);
void remove(Component* component);
Component* getChild(int idx);
private:
vector<Component*> componentVec;
};
#endif //COMPOSITE_H
Composite.cpp
#include <algorithm>
#include "Composite.h"
Composite::Composite() {
}
Composite::~Composite() {
}
void Composite::operation() {
for (auto &i: componentVec) {
i->operation();
}
}
void Composite::add(Component *component) { componentVec.push_back(component); }
void Composite::remove(
Component *component) {
auto it = std::find(componentVec.begin(), componentVec.end(), component);
if (it != componentVec.end()) {
componentVec.erase(it);
}
}
Component *Composite::getChild(int idx) {
return componentVec[idx];
}
Leaf.h
#ifndef LEFT_H
#define LEFT_H
#include "Component.h"
class Leaf: public Component {
public:
Leaf();
~Leaf();
void operation();
};
#endif //LEFT_H
Leaf.cpp
#include "Leaf.h"
#include <iostream>
using namespace std;
Leaf::Leaf() {
}
Leaf::~Leaf() {
}
void Leaf::operation() {
cout<<"Leaf operation....."<<endl;
}
main.cpp
#include "Leaf.h"
#include "Component.h"
#include "Composite.h"
using namespace std;
int main() {
Leaf* l = new Leaf();
l->operation();
Composite* composite = new Composite();
composite->add(l);
composite->operation();
Component* component = composite->getChild(0);
component->operation();
return 0;
}
Component为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component的子部件。
Leaf在组合中表示叶节点对象,叶节点没有子节点。
Composite定义有枝节点行为,用于存储子部件,在Component接口中实现与子部件有关的操作,比如增加Add和删除Remove。
Composite 模式在实现中有一个问题就是要提供对于子节点( Leaf)的管理策略,这里
使用的是 STL 中的 vector,可以提供其他的实现方式,如数组、链表、 Hash 表等。
Composite 模式通过和 Decorator 模式有着类似的结构图, 但是 Composite 模式旨在构造类,而 Decorator 模式重在不生成子类即可给对象添加职责。 Decorator 模式重在修饰, 而Composite 模式重在表示。
Decorator(装饰)
动态地给一个对象添加一些额外的职责(不重要的功能,只是偶然一次要执行),就增加功能来说,装饰模式比生成子类更为灵活。建造过程不稳定,按正确的顺序串联起来进行控制。
GOOD:当你向旧的类中添加新代码时,一般是为了添加核心职责或主要行为。而当需要加入的仅仅是一些特定情况下才会执行的特定的功能时(简单点就是不是核心应用的功能),就会增加类的复杂度。装饰模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择地、按顺序地使用装饰功能包装对象。
decorator.h
#ifndef CLION_TEST_DECORATOR_H
#define CLION_TEST_DECORATOR_H
#include <string>
#include <iostream>
using namespace std;
// 人
class Person
{
private:
string m_strName;
public:
Person(string strName) {
m_strName = strName;
}
Person() {}
virtual void Show()
{
cout<<"装扮的是:"<<m_strName<<endl;
}
};
// 装饰类
class Finery:public Person
{
protected:
Person* m_component;
public:
void Decorate(Person* component) {
m_component = component;
}
void Show() override
{
m_component->Show();
}
};
// T恤
class TShirts:public Finery
{
public:
void Show() final
{
cout<<"T Shirts ";
m_component->Show();
}
};
// 裤子
class BigTrouer: public Finery
{
void Show() final
{
cout<<"Big Trouer ";
m_component->Show();
}
};
#endif //CLION_TEST_DECORATOR_H
main.cpp
#include <iostream>
#include "decorator.h"
using namespace std;
int main() {
system("chcp 65001");
// 装饰模式
Person *p = new Person("小李");
BigTrouer *bt = new BigTrouer();
TShirts *ts = new TShirts();
bt->Decorate(p);
ts->Decorate(bt);
ts->Show();
return 0;
}
输出:
T Shirts Big Trouer 装扮的是:小李
调用关系:
TShirts::Show ==> BigTrouer::Show ==> Person::Show
Facade(外观)
GOOD:为子系统的一组接口提供一个一致的界面。使用户使用起来更加方便。
facade.h
#ifndef CLION_TEST_FACADE_H
#define CLION_TEST_FACADE_H
#include <iostream>
using namespace std;
class Stock1 {
public:
void Buy() {
cout << "股票1买入" << endl;
}
void Sell() {
cout << "股票1卖出" << endl;
}
};
class Stock2 {
public:
void Buy() {
cout << "股票2买入" << endl;
}
void Sell() {
cout << "股票2卖出" << endl;
}
};
class Stock3 {
public:
void Buy() {
cout << "股票3买入" << endl;
}
void Sell() {
cout << "股票3卖出" << endl;
}
};
// 基金类
class Fund {
private:
Stock1 *gu1;
Stock2 *gu2;
Stock3 *gu3;
public:
Fund() {
gu1 = new Stock1();
gu2 = new Stock2();
gu3 = new Stock3();
}
void BuyFund() {
gu1->Buy();
gu2->Buy();
gu3->Buy();
}
void SellFund() {
gu1->Sell();
gu2->Sell();
gu3->Sell();
}
};
#endif //CLION_TEST_FACADE_H
main.cpp
#include "facade.h"
using namespace std;
int main() {
system("chcp 65001");
// 外观模式
Fund* jijin = new Fund();
// 基金购买
jijin->BuyFund();
// 基金赎回
jijin->SellFund();
return 0;
}
使用外观模式的三个场景:
1、在设计初期阶段,应该要有意识的将不同的两个层分离,层与层之间建立外观Facade。
2、在开发阶段。子系统往往因为不断的重构演化而变得越来越复杂,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。
3、在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,为新系统开发一个外观Facade类,来提供涉及粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。
Flyweight(享元)
Proxy(代理)
GOOD:远程代理,可以隐藏一个对象在不同地址空间的事实
虚拟代理:通过代理来存放需要很长时间实例化的对象
安全代理:用来控制真实对象的访问权限
智能引用:当调用真实对象时,代理处理另外一些事
proxy.h
#ifndef CLION_TEST_PROXY_H
#define CLION_TEST_PROXY_H
#include <string>
#include <iostream>
using namespace std;
// 定义接口
class Interface {
public:
virtual void Request() = 0;
};
// 真实类
class RealClass : public Interface {
public:
void Request() final {
cout << "真实的请求" << endl;
}
};
// 代理类
class ProxyClass : public Interface {
private:
RealClass *m_realClass;
public:
void Request() final {
if (m_realClass == nullptr) {
m_realClass = new RealClass();
}
m_realClass->Request();
}
};
#endif //CLION_TEST_PROXY_H
main.cpp
int main() {
ProxyClass* test = new ProxyClass();
test->Request();
return 0;
}
调用关系:
ProxyClass::Request ==> RealClass::Request