您的位置:首页 > 其它

设计模式之二:结构型模式

2018-01-23 17:06 239 查看
设计模式其实某种程度上可以将其看做”阵法“,面对同样的问题可以采用不同的阵法,比如一字长蛇阵、二龙出水阵、八卦阵等,同样的兵力只要布阵得法就能充分发挥军队的战斗力,发挥最佳效能,以一当十不是做梦。设计模式也是同样的道理,同样的人力,如果模式设计得当,则可以在高效完成目标的情况,还可以有效地应对可能发生的需求变化,若是设计不当,被动僵硬不说,甚至防线极为脆弱。但既然说设计模式等同兵书阵法,那么必然不存在万能阵法,必须具体情况具体对待,所以感受设计模式的过程某种程度上确实和古代学习兵书阵法有异曲同工之处,需要不断领悟学习,故以这一系列文章自勉自省,切勿纸上谈兵,又做了街亭马谡!

结构型模式系列是直接沿用了《大话设计模式》一书中的分类。结构型类模式某种程度上场景相关性较强,所描述的更多地是类似于不同形状和材料的柱子,是整体框架的重要组成部分,但并非全部。根据具体的场景,选择合适的柱子,可以让整体框架的基础更稳。

目录:

柱子之一 适配器模式

柱子之二 桥接模式

柱子之三 组合模式

柱子之四 装饰模式

柱子之五 享元模式

柱子之六 代理模式

柱子之七 外观模式

柱子之一: 适配器模式



#include <iostream>

using namespace std;

class Target
{
public:
virtual void Request();
};

class Adaptee
{
public:
void SpecificRequest()
{
cout<<"response from SpecificRequest"<<endl;
}
};

class Adapter : public Target
{
private:
Adaptee* adaptee; //声明该adapter负责的具体adaptee对象

public:
void Request()
{
adaptee->SpecificRequest();
}
};

int main()
{
Target* t = new Adapter();
t->Request(); //"response from SpecificRequest"

return 0;
}


其实可以看到适配器模式和代理模式很相似,只不过适配器模式只是纯起到信息转发和替换,而代理模式可添加额外的扩展操作。

设计阶段:设计中后期,各部已成型,起胶水组装作用。

使用思想:转换与封装。

评分: ★★

柱子之二: 桥接模式



#ifndef _BRIDGE_H
#define _BRIDGE_H

#include <iostream>
#include <string>

class PhoneAPP
{
public:
virtual void Run() = 0; //纯虚函数
};

class GameAPP : public PhoneAPP
{
public:
void Run()
{
cout<<"手机大富翁启动"<<endl;
}
};

class AddressList : public PhoneAPP
{
public:
void Run()
{
cout<<"手机通讯录启动"<<endl;
}
};

class Phone
{
protected:
PhoneAPP* soft;
public:
void SetPhoneAPP(PhoneAPP* app) { soft = app;}
virtual void Run() = 0;
};

class N98 : public Phone
{
public:
void Run()
{
soft->Run();
cout<<"N98的手机软件启动"<<endl;
}
};

class Lumia : public Phone
{
public:
void Run()
{
soft->Run();
cout<<"Lumia的手机软件启动"<<endl;
}
};
#endif

int main()
{
Phone* newN98 = new N98;
N98->SetPhoneAPP(new Game);
N98->Run();//"手机大富翁启动" "N98的手机软件启动"

Phone* newLumia = new Lumia;
Lumian->SetPhoneAPP(new AddressList);
Lumia->Run(); //"手机通讯录启动" "Lumia的手机软件启动
}


设计阶段:设计前期,起到功能分解去耦合的作用

使用思想:分离去耦合

评分: ★★

柱子之三: 组合模式

其实我个人觉得这个名字在中文中翻译的不好,可以叫做”个体和团体统一对待模式“。



//组合模式,让外界对于不同规模的对象都可以拥有同样的处理方式
//比如word中对于单个字进行更改颜色、字体、大小操作和对一段文字进行操作应该是相同的
#include <iostream>
#include <string>
#include <list>

using namespace std;

class Component{//被装饰对象类,抽象类
protected:
string name;

public:
Component(string in)
{
name = in;
}

virtual void Add(Component* c) = 0;
virtual void Remove(Component* c) = 0;
virtual void Display(int depth) = 0;
};

class Leaf:public Component{//叶节点
public:
Leaf(string name):Component(name)
{
}

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

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

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

class Composite:public Component{//叶节点

private:
list<Component*> children;  //这一步是关键,让component能够实现自我组装,堆积木的关键

public:
Composite(string name):Component(name)
{

}

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

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

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

list<Component*>::iterator iter;
for (iter = children.begin(); iter != children.end(); iter++)
{
(*iter)->Display(depth+2);
}
}
};

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->Display(2);

//Composite A;
cout<<sizeof(A)<<endl;

return 0;
}




设计阶段:设计前期,抽象封装作用,消除个体对象和组合对象之间在client眼中的差异

使用思想:抽象封装

评分: ★★★

柱子之四: 装饰模式





//decorate model装饰者模式
//用于给某些类动态添加功能,虽然添加了一些功能,但人还是人,只不过是装饰后的人
#include <iostream>
#include <string>

using namespace std;

class Person{//被装饰对象类,抽象类
public:
virtual void show()
{
cout<<"Person"<<endl;
}

};

class Decorate:public Person{//所有装饰类的基类
public:
void setPerson(Person* dePerson)
{//设置该类所装饰的对象,该函数传递的是一Person类的指针,所以也可以由子类初始化
person=dePerson;
}

void show()
{//显示函数,这一函数是一个虚函数,可以由子类实现
//而且,person是一个基类指针,具体指向由用户决定
if(person!=NULL)
person->show();
}

protected:
Person *person; //核心便是这个将person作为私有变量的操作,从而实现了信息的嵌套传递
};

class Tshirts:public Decorate{
public:
void addFunction1()
{//特有操作
cout<<"function1 added"<<endl;
}

void show()
{
addFunction1();//子类添加的功能
person->show();
//Decorate::show();//被装饰对象原有的功能
}
};

class Trouser:public Decorate{
public:
void addFunction2()
{//特有操作
cout<<"function2 added"<<endl;
}

void show()
{
addFunction2();//子类添加的功能
person->show();
//Decorate::show();//子被装饰对象原有的功能
}
};

int main()
{
Person* person=new Person();
//person->show();

Tshirts* tshir=new Tshirts();
tshir->setPerson(person);
//tshir->show();

Trouser* trou=new Trouser();
trou->setPerson(tshir);
//trou->show();

Tshirts* newTshir = new Tshirts();
newTshir->setPerson(trou);
newTshir->show();

return 0;
}




设计阶段:设计中前期,随着外部处理模块的增加,封装出附加模块迭代嵌套的效果

使用思想:迭代嵌套

评分: ★★★

柱子之五: 享元模式





#pragma once

#include <hash_map>
#include <iostream>
#include <string>

using namespace std;

class User
{
friend class Flyweight;
private:
string name;
public:
User(string _in) : name(_in) {}
string getName() {return name;}
};

class Flyweight
{
private:
//Íⲿ״̬
string outsideState;
protected:
//Íⲿ״̬
const string extrainsic;
public:
Flyweight(string _ex) : extrainsic ( _ex) {}

//¶¨ÒåÒµÎñ²Ù×÷
virtual void operate(User _user) = 0;

string getOutsideState()
{
return outsideState;
}

void setOutsideState(User _user)
{
outsideState = _user.getName();
}

string getType()
{
return extrainsic;
}

};

class ConcreteFlyweight : public Flyweight
{
public:
ConcreteFlyweight(string ex) :Flyweight(ex) {}

void operate(User _user)
{
setOutsideState(_user);
//¸ù¾ÝÍⲿÂß¼­½øÐÐÒµÎñ´¦Àí
cout << "Ä£°å" << getType()<<"½«½ÓÊÜ´¦ÀíÐÅÏ¢:" <<getOutsideState()<< endl;
}
};

class FlyweightFactory
{
private:
static hash_map<string, Flyweight*> pool;
public:
Flyweight* getFlyweight(string ex)
{
hash_map<string, Flyweight*>::iterator it = pool.find(ex);
if (it == pool.end())
{
cout << "Creat Flyweight" << endl;
pool[ex] = new ConcreteFlyweight(ex);
}
return pool[ex];
}

int getFlyweightCount() {
return pool.size();
}
};

hash_map<string, Flyweight*> FlyweightFactory::pool = hash_map<string,Flyweight*>();

int main()
{
FlyweightFactory Wfactory;
Flyweight* fx = Wfactory.getFlyweight("²úƷչʾ");
fx->operate(User("С²Ë"));

Flyweight* fy = Wfactory.getFlyweight("²úƷչʾ");
fy->operate(User("´óÄñ"));

Flyweight* fz = Wfactory.getFlyweight("²úƷչʾ");
fz->operate(User("½¿½¿"));

Flyweight* fn = Wfactory.getFlyweight("²©¿Í");
fn->operate(User("ÌÒ¹ÈÁùÏÉ"));

Flyweight* fm = Wfactory.getFlyweight("²©¿Í");
fm->operate(User("ÄϺ£öùÉñ"));

cout << "\nµÃµ½µÄÍøÕ¾·ÖÀà×ÜÊýΪ£º " << Wfactory.getFlyweightCount()<<endl;
return 0;
}




总结

1、面向对象很好的解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight设计模式主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。

2、Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理。

3、享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。另外它将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。

享元模式和对象池的区别

享元模式可以实现对象池。对象池着重在对象的复用,池中的每个对象都是可替换的,从同一个池中获得A对象和B对象对客户端来讲是完全相同的,主要解决复用。享元模式侧重共享问题,如何建立多个可共享的细粒度对象则是其关注的重点。

设计阶段:设计前期,需要分清出场景中的变和不变的部分,将可共享的部分提炼出来

使用思想:分离解析

评分: ★★★

柱子之六: 代理模式



//代理模式,对真实对象的访问通过代理完成,影分身模式
//既然是影分身那么其实可能和本体存在差异,比如功能阉割
#include <iostream>

using namespace std;

//代理和真实对象的公用接口
class Subject{
public:
virtual void request()=0;
virtual void behavior()=0;
};

//真实对象
class RealSubject:public Subject{
public:
void request()
{
cout<<"real request for real subject"<<endl;
}

void behavior()
{
cout<<"real behavior from real subject"<<endl;
}
};

//代理,代理通过访问真实对象完成和真实对象相同的操作
class Proxy:public Subject{
public:
void request()
{
cout<<"first make some pre-operations"<<endl;
subject.request();
}

void behavior()
{
cout<<"prepared work before the real behavior"<<endl;
subject.behavior();
}

private:
RealSubject subject; //关键也是这一目标对象作为隐藏的内部属性,从而可以自定义权限行为
};

int main()
{
//网页加载时图片的加载就是使用的代理,网页打开时,图片是一张一张出现的,先于图片出现的就是代理
Proxy* proxy=new Proxy();
proxy->request();
proxy->behavior();
return 0;
}




代理模式应该算是在软件设计中经常用到的设计模式,自由度大且使用场景多样,可自由定制行为,具有诸多的使用场景。

设计阶段:设计全期,抽象封装,定义额外行为

使用思想:转换和封装

评分: ★★★

柱子之七: 外观模式



//外观模式:给接口提供一致的外观,管家助手模式
//当客户需要使用到子系统的多个功能时,客户如果逐个去调用每一个功能会引起较大代码量;
//并存在潜在的错误可能性;
//如果这些功能都位于不同的类中,客户需要去了解每一个类
//解决方法是:为所有类的接口提供一个一致的接口,这一接口提供了所有用户需要的操作;
//通俗理解:木兰从军,需要买各种从军用品如马、马鞍、配剑、靴子等,这些东西都不在同一个店里,从而导致木兰东奔西走;
//现在如果有一家专门的军需用品店,那木兰在这家店里就可以买到所有需要的物品

#include<iostream>

using namespace std;

//功能一
class SubSystemOne{
public:
void methodOne()
{
cout<<"method One"<<endl;
}
};

//功能二
class SubSystemTwo{
public:
void methodTwo()
{
cout<<"method Two"<<endl;
}
};

//功能三
class SubSystemThree{
public:
void methodThree()
{
cout<<"method Three"<<endl;
}
};

//提供一致的功能接口
class Facade{
public:
void methodA()
{
systemOne.methodOne();
systemTwo.methodTwo();
systemThree.methodThree();
cout<<"Three Operation"<<endl;
}

void methodB()
{
systemOne.methodOne();
cout<<"Just one operation"<<endl;
}

private:
SubSystemOne systemOne;
SubSystemTwo systemTwo;
SubSystemThree systemThree;
};

int main()
{
Facade facade;
facade.methodA();
facade.methodB();

return 0;
}




设计阶段:设计中后期,封装遗留代码,定义组装行为

使用思想:封装

评分: ★★★
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息