C++设计模式
1、创建型模式(隔离变化、封装变化:new的解耦)(new就代表具体,代码绑着具体类会更脆弱,缺乏弹性)
1、工厂模式
1、1简单工厂模式(编程习惯,创建对象的同时隐藏是实现细节)
缺点:简单工厂违背了开放封闭原则(添加新的产品会改变原有代码)
总结:简单工厂模式最大的优点在于工厂类中包含了必要的逻辑判断根据用户选择的条件动态实例化相关的类,对客户端来说,去除了与具体产品的依赖,但是当需求变动的时候,比如生产一个新的产品,需要对原有的类进行修改,违反了开放封闭原则
1、2工厂模式
定义:工厂模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法把类的实例化 推迟到子类。工厂方法使用了多态,克服了简单工厂违背的开放封闭原则
缺点:没有隐藏工厂的实现过程,new和工厂有耦合,工厂模式违反了开闭原则
解决方式:1)简单工厂+工厂模式
2}IOC机制:引入IOC机制,,控制翻转,把对象的创建、赋值、管理工作都交以代码以外的容器实现,也就是对象的创建由外部资源完成,由容器代替开发人员管理对象,目的是为了减少对代码的改动,实现不同的功能(解耦合)
代码
#include <iostream> #include <string> using namespace std; // 水果类 class Fruit { public: virtual void GetFruit() = 0; }; class Apple : public Fruit { public: void GetFruit() { cout << "我是苹果......." << endl; } }; class Pear : public Fruit { public: void GetFruit() { cout << "我是梨......." << endl; } }; class Banana:public Fruit { public: void GetFruit() { cout << "我是香蕉......." << endl; } }; class Plum : public Fruit { public: void GetFruit() { cout << "我是李子......" << endl; } }; class AbsFactory { public: virtual Fruit* CreateProduct() = 0; }; // 苹果工厂 class AppleFactory :public AbsFactory { public: Fruit* CreateProduct() { return new Apple; } }; class PearFactory :public AbsFactory { public: Fruit* CreateProduct() { return new Pear; } }; class BananaFactory :public AbsFactory { public: Fruit* CreateProduct() { return new Banana; } }; class PlumFactory:public AbsFactory { public: Fruit * CreateProduct() { return new Plum; } }; template <typename T> class DynCreatObj { public: //成员函数模版 template <typename Obj> void registerType(string type) //将类型保存到map容器中 { function<T *()> func = [](){return new Obj();}; if(m.find(type) == m.end()) { m.emplace(type,func); } else { throw(string("type已存在")); } } T * getObj(string type) { function<T* ()> func; if(m.find(type) != m.end()) { func = m[type]; return func(); } else { throw(string("type不存在")); } } private: map<string,function<T *()>> m; //"A" new A(); "B" new B(); }; int main() { string str; DynCreatObj<AbsFactory> dny_obj; dny_obj.registerType<AppleFactory>("apple"); dny_obj.registerType<BananaFactory>("banana"); cin >> str; AbsFactory *factory = dny_obj.getObj(str); Fruit *f = factory->CreateProduct(); f->GetFruit(); return 0; }
2、抽象工厂模式
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无须指定他们的具体类。
优点:在有多个业务品种、业务分类时,通过抽象工厂模式生产需要的对象是一个非常好的解决方式
缺点:加入产品族中要加入一个新的产品,不仅要实现产品类,还有创建相关的工厂接口
代码
#include<iostream> using namespace std; //抽象猫类 class Cat{ public: virtual string getType() = 0; }; //白颜色猫 class WhiteCat:public Cat{ public: WhiteCat():Cat(),m_type("WhiteCat"){ } string getType(){ cout << m_type << endl; return m_type; } private: string m_type; }; //黑色猫类 class BlackCat:public Cat{ public: BlackCat():Cat(),m_type("BlackCat"){ } string getType(){ cout << m_type << endl; return m_type; } private: string m_type; }; //抽象狗类 class Dog{ public: virtual string getType() = 0; }; //白色狗类 class WhiteDog:public Dog{ public: WhiteDog():Dog(),m_type("WhiteDog"){ } string getType(){ cout << m_type << endl; return m_type; } private: string m_type; }; //黑色狗类 class BlackDog:public Dog{ public: BlackDog():Dog(),m_type("BlackDog"){ } string getType(){ cout << m_type << endl; return m_type; } private: string m_type; }; //抽象工厂类 class Pet { public: virtual Cat* createCat() = 0; virtual Dog* createDog() = 0; }; //白色宠物工厂 class WhitePetFactory { public: Cat* createCat(){ return new WhiteCat(); } Dog* creatDog(){ return new WhiteDog(); } }; //黑色宠物工厂 class BlackPetFactory { public: Cat* createCat(){ return new BlackCat(); } Dog* creatDog(){ return new BlackDog(); } };
3、单例模式
定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这实例(比如整个程序只有一个日志文件)
应用:单例模式主要作用是确保一个类只有一个实例存在。单例模式可以用在建立目录、数据库连接等需要单线程操作的场合,用于实现对系统资源的控制
1、懒汉单例模式
定义:第一次引用类时,才进行对象实例化
非线程安全的懒汉单例模式代码
class Singleton { public: static Singleton* getInstance(); ~Singleton(){} private: Singleton(){} //构造函数私有,防止通过拷贝构造,赋值运算实例化对象 Singleton(const Singleton& obj) = delete; //明确拒绝 Singleton& operator=(const Singleton& obj) = delete; //明确拒绝 static Singleton* m_pSingleton; }; Singleton* Singleton::m_pSingleton = NULL; Singleton* Singleton::getInstance() { if(m_pSingleton == NULL) { m_pSingleton = new Singleton; } return m_pSingleton; }
线程安全的懒汉单例模式代码(加了把锁,访问静态变量变成了原子操作)
std::mutex mt; class Singleton { public: static Singleton* getInstance(); private: Singleton(){} //构造函数私有 Singleton(const Singleton&) = delete; //明确拒绝 Singleton& operator=(const Singleton&) = delete; //明确拒绝 static Singleton* m_pSingleton; }; Singleton* Singleton::m_pSingleton = NULL; Singleton* Singleton::getInstance() { if(m_pSingleton == NULL) { mt.lock(); if(m_pSingleton == NULL) { m_pSingleton = new Singleton(); } mt.unlock(); } return m_pSingleton; }
2、饿汉单例模式
定义:类加载时,就进行对象实例化
//饿汉式:线程安全,注意一定要在合适的地方去delete它 class Singleton { public: static Singleton* getInstance(); private: Singleton(){} //构造函数私有 Singleton(const Singleton&) = delete; //明确拒绝 Singleton& operator=(const Singleton&) = delete; //明确拒绝 static Singleton* m_pSingleton; }; Singleton* Singleton::m_pSingleton = new Singleton(); Singleton* Singleton::getInstance() { return m_pSingleton; }
4、建造者模式(定义不太好)
定义:将一个复杂对象的构建与他的表示分离,是的同样的构建过程可以创建不同的表示
适用场景:
- 相同的方法,不同的执行顺序,产生不同的结果时,可以使用建造者模式
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,可以使用该模式
- 产品类非常复杂,或者产品类中的方法调用顺序不同产生了不同的效能,使用建造者模式
代码
#include <iostream> #include <string> using namespace std; // 一个产品由零件1 零件2 构成 //具体的产品类 class Product { public: void setPart1(string part1) { m_part1 = part1; } void setPart2(string part2) { m_part2 = part2; } string getPart1(){ cout << m_part1 << endl; return m_part1; } string getPart2(){ cout << m_part2 << endl; return m_part2; } private: string m_part1; string m_part2; }; //抽象建造类,提供建造接口。 class OrderBuilder { public: virtual ~OrderBuilder() { cout << "~OrderBuilder()" << endl; } virtual void setOrderPart1() = 0; virtual void setOrderPart2() = 0; virtual Product* getProduct() = 0; }; //具体的建造类 class FirstOrderBuilder : public OrderBuilder { public: FirstOrderBuilder() { m_Product = new Product; } ~FirstOrderBuilder() { cout << "~FirstOrderBuilder()" << endl; delete m_Product; m_Product = NULL; } void setOrderPart1() { m_Product->setPart1("first part1"); } void setOrderPart2() { m_Product->setPart2("first part2"); } Product* getProduct() { return m_Product; } private: Product* m_Product; }; //具体的建造类 class SecondOrderBuilder : public OrderBuilder { public: SecondOrderBuilder() { m_Product = new Product; } ~SecondOrderBuilder() { cout << "~SecondOrderBuilder()" << endl; delete m_Product; m_Product = NULL; } void setOrderPart1() { m_Product->setPart1("second part1"); } void setOrderPart2() { m_Product->setPart2("second part2"); } Product* getProduct() { return m_Product; } private: Product* m_Product; }; //Director类,负责管理实例创建的依赖关系,指挥构建者类创建实例 class Director { public: Director(OrderBuilder* builder) : m_pOrderBuilder(builder) { } void construct() { m_pOrderBuilder->setOrderPart1(); m_pOrderBuilder->setOrderPart2(); } private: OrderBuilder* m_pOrderBuilder; }; int main() { OrderBuilder* mBuilder = new SecondOrderBuilder; Director* director = new Director(mBuilder); director->construct(); Product* order = mBuilder->getProduct(); order->getPart1(); order->getPart2(); delete director; director = NULL; delete mBuilder; mBuilder = NULL; return 0; }
5、原型模式
定义:允许动态的增加或减少产品类,用原型实例指定创建对象的种类,并且通过这些原型创建新的对象
特点:
性能优良,原型模式是在内存二进制流的复制,要比直接new一个对象性能好,特别是在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
逃避构造函数的约束:这既是优点也是缺点,直接在内存中复制,构造函数是不会执行的,因此减少了约束,需要在实际应用时进行权衡考虑。
使用场景:
资源优化:类初始化需要消化非常多的资源;
性能和安全要求的场景:通过new产生一个对象需要非常繁琐的数据准备或者访问权限,可以使用原型模式;
一个对象多个修改者的场景:一个对象需要提供给其他对象访问,而且各个调用者都需要修改其值时可以考虑使用原型模式复制多个对象供调用者使用。
代码
#include <iostream> using namespace std; //具体的实现类 class Product { public: Product(int id, string name):m_id(id),m_name(name) { cout << "Product() id address:" << &m_id << endl; cout << "Product() name address:" << &m_name << endl; } //关键代码拷贝构造函数 Product(const Product& obj) { this->m_id = obj.m_id; this->m_name = obj.m_name; cout << "Product(const Product& obj) id address:" << &m_id << endl; cout << "Product(const Product& obj) name address:" << &m_name << endl; } //关键代码克隆函数,返回return new Sheep(*this) Product* clone() { return new Product(*this); } void show() { cout << "id :" << m_id << endl; cout << "name:" << m_name.data() << endl; } private: int m_id; string m_name; }; int main() { Product* s1 = new Product(1, "abs"); s1->show(); Product* s2 = s1->clone(); s2->show(); delete s1; s1 = NULL; delete s2; s2 = NULL; return 0; }
2、结构型模式(隔离变化,封装变化:类内部结构、对象之间结构的解耦)
1、适配器模式
定义:将一个类的接口变换成客户端期待的另一种接口(改变接口,统一接口),适配器让原本接口不兼容的类可以合作无间
优点:通过创建适配器进行接口转换,让不兼容的接口变成兼容,可以让客户从实现的接口解耦
场景:修改一个已经投产中的系统时,需要对系统进行扩展,此时使用一个已有的类,但这个类不符合系统中的接口,这时使用适配器模式是最合适的,它可以将不符合系统接口的类进行转换,转换成符合系统接口的、可以使用的类。
代码
#include<iostream> using namespace std; //源角色 class ShuiJiao{ public: void makeShuiJiao(){ cout<<"调制菜料"<<endl; cout<<"擀面皮"<<endl; cout<<"包饺子"<<endl; } }; //抽象目标类 class HumDun{ public: virtual void makeHumDun()=0; }; //适配类 class FoodAdapter:public HumDun,public ShuiJiao{ public: void makeHumDun(){ makeShuiJiao(); cout<<"水饺与馄饨步骤一样"<<endl; } }; int main(){ FoodAdapter foodAdapter; foodAdapter.makeShuiJiao(); foodAdapter.makeHumDun(); }
2、代理模式(具体类)(这个代码和装饰没有什么区别啊)
定义:为另一个对象提供一个替身或者占位符来控制对这个对象的访问
优点:使用代理模式创建代表对象,让代表对象来控制某对象的访问,被代理的对象可以是远程的对象,创建开销大的对象或需要安全控制的对象
特点:
■ 职责清晰:真实的角色实现实际的业务逻辑,不用关心其他非本职的事务,通过后期的代理完成附加的事务,附带的结果就是编程简洁清晰。
■ 高扩展性:具体主题角色随需求不同可能有很多种,但只要实现了接口,代理类就完全可以在不做任何修改的情况下代理各种真实主题角色。
■ 智能化:代理类可以在运行时才确定需要去代理的真实主题,这是一种强大的功能。
代码:
#include<iostream> using namespace std; //IGamePlayer接口对游戏玩家进行抽象 class IGamePlayer{ public: virtual void killBoss() = 0;//杀怪 virtual void upGrade() = 0;//升级 }; //GamePlayer实现IGamePlayer接口中的方法 class GamePlayer:public IGamePlayer{ public: GamePlayer(string name){ m_name = name; } void killBoss(){ cout<<m_name<<"在打怪"<<endl; } void upGrade(){ cout<<m_name<<"成功升级"<<endl; } private: string m_name; }; //GamePlayerProxy是代理类 class GamePlayerProxy:public IGamePlayer{ public: GamePlayerProxy(IGamePlayer* player){ this->player = player; } void killBoss(){ this->log(); player->killBoss(); } void upGrade(){ player->upGrade(); this->count(); } private: IGamePlayer* player = NULL; void log(){ cout<<"打怪时间XXX"<<endl; } void count(){ cout<<"升一级耗费5小时"<<endl; } }; int main(){ IGamePlayer* player = new GamePlayer("AA"); IGamePlayer* prox = new GamePlayerProxy(player); prox->killBoss(); prox->upGrade(); delete player; player = NULL; delete prox; prox = NULL; }
3、包装模式
定义:动态的给一个对象增加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
优点:
■ 装饰类和被装饰类可以独立发展,而不会相互耦合。即 Component 类无须知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构件。
■ 装饰模式是继承关系的一个替代方案。装饰类Decorator,不管装饰多少层,返回的对象还是Component。、
■ 装饰模式可以动态地扩展一个实现类的功能。
缺点:多层的装饰还是比较复杂
使用场景
■ 需要扩展一个类的功能,或给一个类增加附加功能。
■ 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
■ 需要为一批类进行改装或加装功能。装饰模式是对继承的有力补充。单纯使用继承时,在一些情况下就会增加很多子类,而且灵活性差,维护也不容易。装饰模式可以替代继承,解决类膨胀的问题
代码:
//包装和代理 一个是组合抽象类 一个是组合具体类 class AbsCal { public: virtual double get_result(string op) = 0; }; //已有类:升级功能 --代理 class Cal : public AbsCal { public: Cal(double a, double b) : m_a(a), m_b(b) { } void setAdd(Operation *add) { m_add = add; } void setSub(Operation *sub) { m_sub = sub; } double get_result(string op) { double result; if(op == "+") { result = m_add->get_result(m_a,m_b); } else if(op == "-") { result = m_sub->get_result(m_a,m_b); } return result; } private: double m_a; double m_b; Operation *m_add; Operation *m_sub; }; class File : public AbsCal { public: File(AbsCal *cal) : m_cal(cal) { } double get_result(string op) { double result = m_cal->get_result(op); saveFile(); return result; } void saveFile() { cout << "Save file" << endl; } private: AbsCal *m_cal; }; class Sqlite3 : public AbsCal { public: Sqlite3(AbsCal *cal) : m_cal(cal) { } double get_result(string op) { double result = m_cal->get_result(op); saveFile(); return result; } void saveFile() { cout << "Save sqlite3" << endl; } private: AbsCal *m_cal; }; class MySql : public AbsCal { public: MySql(AbsCal *cal) : m_cal(cal) { } double get_result(string op) { double result = m_cal->get_result(op); saveFile(); return result; } void saveFile() { cout << "Save Mysql" << endl; } private: AbsCal *m_cal; }; void test() { AbsCal *cal = new Cal(5,6); AbsCal *cal2 = new File(cal); //抽象 AbsCal *cal3 = new MySql(cal2); cout << cal3->get_result("+") << endl; } 装饰:和装饰器类 #include <iostream> #include <sstream> using namespace std; //模版 //T类型对象返回string类型 template <class T> string MyConvertToStr(T obj) { stringstream ss; ss << obj; return ss.str(); } //基类 class Beverage { public: virtual string getDescription() = 0; virtual double cost() = 0; protected: string m_Description; }; //还是抽象类,加东西抽象 class CondimentDecorate :public Beverage { public: virtual string getDescription() = 0; protected: //构造函数2 CondimentDecorate(){} }; //装饰类1:Soy class Soy :public CondimentDecorate { public: //构造函数 Soy(Beverage *pBeverage):m_pBeverage(pBeverage){} string getDescription() { return m_pBeverage->getDescription() + ",加了酱油了"; } double cost() { return 0.1 + m_pBeverage->cost(); } private: //持有被装饰的对象(基类) Beverage *m_pBeverage; }; //装饰类2:Milk class Milk :public CondimentDecorate { public: Milk(Beverage *pBeverage) :m_pBeverage(pBeverage) {} string getDescription() { return m_pBeverage->getDescription() + ",加了牛奶了"; } double cost() { return 5+ m_pBeverage->cost(); } private: //持有被装饰的对象 Beverage *m_pBeverage; }; class Lattee :public Beverage { public: Lattee() { m_Description = "拿铁"; } string getDescription() { return m_Description; } double cost() { return 13; } }; class Expresso :public Beverage { public: Expresso() { m_Description = "浓缩咖啡"; } string getDescription() { return m_Description; } double cost() { return 13; } }; class Mocha :public Beverage { public: Mocha() { m_Description = "摩卡"; } string getDescription() { return m_Description; } double cost() { return 13; } }; int main(void) { Beverage* pBeverage = new Expresso(); cout << pBeverage->getDescription() << "价格是" << MyConvertToStr(pBeverage->cost()) << endl; Beverage* pBeverage2 = new Mocha(); pBeverage2 = new Soy(pBeverage2); pBeverage2 = new Soy(pBeverage2); cout << pBeverage2->getDescription() << "价格是" << MyConvertToStr(pBeverage2->cost()) << endl; system("pause"); return 0; }
4、桥接模式
定义:将抽象和实现解耦,使得两者可以独立的变化
优点:
■ 抽象和实现分离是桥梁模式的主要特点,是为了解决继承的缺点而提出的设计模式。在该模式下,实现可以不受抽象的约束,不用绑定在一个固定的抽象层次上。
■ 实现对客户透明,客户端不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装。
■ 提高灵活性和扩展性。
使用场景
■ 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展;
■ 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
代码
#include<iostream> using namespace std; //抽象颜色类 class Color{ public: virtual string getColor() = 0; }; //抽象形状类 class AbstractShape{ public: virtual void draw(Color* color) = 0; }; //具体形状类 class Circle:public AbstractShape{ void draw(Color* color){ cout<<"draw a "+ color->getColor() +" Circle"<<endl; } }; //具体形状类 class Square:public AbstractShape{ void draw(Color* color){ cout<<"draw a "+ color->getColor() +" Square"<<endl; } }; //具体颜色类 class Red:public Color{ string getColor(){ return "red"; } }; //具体颜色类 class Green:public Color{ string getColor(){ return "Green"; } }; int main(){ Color* color = new Green(); AbstractShape* shape = new Square(); shape->draw(color); delete color; color = NULL; delete shape; shape = NULL; }
5、享元模式
定义:享元模式是对象池的一种实现。类似于线程池,线程池可以避免不停的创建和销毁多个对象,消耗性能。
作用:缓存共享对象,降低内存消耗
优点:享元模式的优点在于大幅减少内存中对象的数量,降低程序内存的占用,提高性能。
缺点:
■ 享元模式增加了系统的复杂性,需要分出外部状态和内部状态,而且内部状态具有固化特性,不应该随外部状态改变而改变,这使得程序的逻辑复杂化。
■ 享元模式将享元对象的状态外部化,而读取外部状态使得运行时间变长。
使用场景:
■ 系统中有大量的相似对象,这些对象耗费大量的内存。
■ 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,即对象没有特定身份。
■ 需要缓冲池的场景。
代码
#include<iostream> using namespace std; //棋子接口Chesspiece是抽象享元,该接口中规范一个落子put()方法,对棋子的坐标进行定位通过参数的形式将外部状态传入 class Chesspiece{ public: virtual void put(int x,int y)=0; }; //棋子具体享元ChesspieceFlyweight实现棋子接口Chesspiece class ChesspieceFlyweight:public Chesspiece{ public: ChesspieceFlyweight(string color){ this->color = color; } void put(int x,int y){ cout<<color<<"子在("<<x<<","<<y<<")落子"<<endl; } private: string color; }; //棋子工厂ChesspieceFactory是享元工厂,负责创建和管理棋子 class ChesspieceFactory{ public: static Chesspiece* WHITE; static Chesspiece* BLACK; public: static Chesspiece* getChessPiece(string color){ if(color == "白"){ return WHITE; } else if(color == "黑"){ return BLACK; } return NULL; } }; Chesspiece* ChesspieceFactory::BLACK = new ChesspieceFlyweight("黑"); Chesspiece* ChesspieceFactory::WHITE = new ChesspieceFlyweight("白"); int main(){ ChesspieceFactory chesspieceFactory; Chesspiece* p1 = chesspieceFactory.getChessPiece("黑"); p1->put(1,1); Chesspiece* p2 = chesspieceFactory.getChessPiece("白"); p2->put(1,1); delete p1; p1 = NULL; delete p2; p2 = NULL; }
6、组合模式
定义:将对象组合成树形结构以表示“部分—整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性
优点:
■ 高层模块调用简单。一棵树形机构中的所有节点都是 Component,局部和整体对调用者来说没有任何区别,即高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
■ 节点自由增加。使用组合模式后,如果想增加一个树枝节点、树叶节点只需要找到其父节点即可。
缺点:
■ 不易控制树枝构件的类型;
■ 不易使用继承的方法来增加新的行为。
使用场景:
■ 需要描述对象的部分和整体的等级结构,如树形菜单、文件和文件夹管理。
■ 需要客户端忽略个体构件和组合构件的区别,平等对待所有的构件。组合模式也是应用广泛的一种设计模式。
代码:
#include<iostream> #include <list> #include <memory> #include <stdio.h> #include <string> using namespace std; // class Company { public: virtual string getInfo() = 0; virtual string getName() { return name; } virtual string getType() = 0; protected: string name; string position; int salary; }; class ConcreteCompany :public Company { public: ConcreteCompany(string name, string position, int salary) { this->name = name; this->position = position; this->salary = salary; } void add(Company* company) { shared_ptr<Company> temp(company); companyList.push_back(temp); } string getType() { return "ConcreteCompany"; } void remove(string companyName) { list<shared_ptr<Company>>::iterator iter = companyList.begin(); for (; iter != companyList.end(); iter++) { if ((*iter).get()->getName() == companyName) { companyList.erase(iter); return; } } } list<shared_ptr<Company>> getChild() { return companyList; } string getInfo() { string info = ""; info = "名称:" + this->name; info = info + "\t职位:" + this->position; info = info + "\t薪水:" + to_string(this->salary); return info; } private: list<shared_ptr<Company>> companyList; }; class Employee :public Company { public: Employee(string name, string position, int salary) { this->name = name; this->position = position; this->salary = salary; } string getType() { return "Employee"; } string getInfo() { string info = ""; info = "名称:" + this->name; info = info + "\t职位:" + this->position; info = info + "\t薪水:" + to_string(this->salary); return info; } }; void disPlay(ConcreteCompany* root) { cout << root->getInfo() << endl; list<shared_ptr<Company>> tmp = root->getChild(); list<shared_ptr<Company>>::iterator iter = tmp.begin(); for (; iter != tmp.end(); iter++) { if ((*iter).get()->getType() == string("Employee")) { cout << (*iter).get()->getInfo() << endl; } else { disPlay((ConcreteCompany*)(*iter).get()); } } } int main() { ConcreteCompany* root = new ConcreteCompany("张三", "CEO", 100000); ConcreteCompany* develop = new ConcreteCompany("李四", "研发组长", 100000); ConcreteCompany* sale = new ConcreteCompany("王二", "销售组长", 100000); Employee *e1 = new Employee("A", "研发",200); Employee *e2 = new Employee("B", "销售", 200); Employee *e3 = new Employee("C", "研发", 200); Employee *e4 = new Employee("D", "销售", 200); root->add(develop); root->add(sale); develop->add(e1); develop->add(e3); sale->add(e2); sale->add(e4); disPlay(root); develop->remove("A"); disPlay(root); delete root; root = NULL; }
7、外观模式
定义:改变接口的原因是为了简化接口,他将一个或数个类的复杂的一切都隐藏在背后,只露出一个美好干净的外观;提供了一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层接口,让子系统更容易使用
比如要构建一个家庭影院,要打开爆米花机,调暗灯光,放下屏幕,打开投影仪,在打开DVD,然后开始播放电影,但是现在我们把这些操作封装到watch moive这个接口中,那么想看的电影的时候,只需要调用一个接口,一口气直接全部搞定
优点:
■ 减少系统的相互依赖,所有的依赖都是对Façade对象的依赖,与子系统无关。
■ 提高灵活性,不管子系统内部如何变化,只要不影响Facade对象,任何活动都是自由的。
■ 提高安全性,Facade中未提供的方法,外界就无法访问,提高系统的安全性。
注意外观模式最大的缺点是不符合开闭原则,对修改关闭,对扩展开放。
场景使用:
■ 为一个复杂的模块或子系统提供一个供外界访问的接口。
■ 子系统相对独立,外界对子系统的访问只要黑箱操作即可。
■ 预防风险扩散,使用Façade进行访问操作控制
代码:
#include<iostream> using namespace std; class Airport{ public: void bookTicket(string from,string to){ cout<<"订购了从"+ from +"到" + to + "的机票"<<endl; } }; class Hotel{ public: void reserve(int days){ cout<<"定了"<<days<<"天的房间"<<endl; } }; class Chauffeur{ public: void drive(string to){ cout<<"司机开车去"+to<<endl; } }; class Secretary{ public: void trip(string to,int days){ airport.bookTicket("上海",to); chauffeur.drive("机场"); hotel.reserve(days); } private: Chauffeur chauffeur; Hotel hotel; Airport airport; }; int main(){ Secretary s; cout<<"老板告诉秘书出差10天"<<endl; s.trip("青岛",10); }
3、行为型模式(隔离变化,封装变化:将动作封装成对象,从类中解耦)(重点,挺重要的)
1、模版方法模式
定义:模版方法定义了一个算法步骤,并允许子类为一个或多个步骤提供实现;模版方法实在一个方法中定义一个算法的骨架,其中的任何步骤都可以抽象的,有子类负责实现,这样可以确保算法的结构保持不变,同时类提供部分实现。
比如:学生都需要去上课,其上课的具体流程是上课、听课、下课,但是不同类学生听课(上课、下课)的具体内容不同
适用场景:1、一次性实现算法不变的部分,将可变的部分留给子类
2、各个子类中的公共行为提取出来并集中到一个公共父类避免代码重用
3、通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制
2、策略模式
定义:定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户(将每一个算法策略封装到接口中,根据需要设定的策略,使具体实现和策略解耦)
优点:定义算法族,使用继承可以把公共的代码移到父类中,提高复用性;算法的变化和客户端分离,提高可扩展性
缺点:类过多---策略模式造成很多的策略类,每个具体策略类都会产生一个新类,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
比如有鸭子类,那么鸭子可以飞可以抽象成行为类,也就是算法族,不同的鸭子有不同的飞行方式,有的鸭子在天上飞,有的鸭子在地上飞,有的鸭子不会飞,此时抽象出公共接口组合到鸭子类,这样在增加在火箭上飞的时候,就不会影响到原有代码,提高了代码的可扩展性。
3、观察者模式
(降低了观察者和主题的耦合度)
定义:定义了对象之间一对多的依赖,这样一来,当一个对象改变时,它的所有依赖者都会收到通知并自动更新
(主题只知道观察者实现了某个接口,并不知道观察者具体的类是谁,做了什么细节,所以任何时候可以增加新的观察者,也可以删除某些观察者),有新的观察者出现时,主题代码不需要改变,主题只会发送通知给所有实现了观察接口的对象,改变主题或观察者其中一方,并不会影响另一方,两者低耦合)
比如:国家气象局观察天气(主题),可以把天气的变化发送给华为、小米、oppo的手机,那么vivo也相当观察者,直接加入就可以,oppo也可以直接退出,完全不会影响原有代码,说明类之间的耦合度低。
优点:具体主题和具体观察者是松耦合关系;观察者模式满足“开-闭原则”
缺点:1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。(性能浪费)
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
4、责任链模式
定义:(多用于有if else的场景下)将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
优点:1、解耦:请求发起者和请求响应者进行解耦。链的创建由使用者(客户端)创建。
2、动态组合:可以运行时动态组合链,根据需求增加或者减少处理节点。
3、易修改:处理节点独立变化,只处理自己关心的工作,修改方便;易扩展:如果有新的处理需求,创建新的处理节点,然后使用者重新建链。是符合开闭原则的。
缺点:1、执行未处理:没有明确接收者,或者配置不当,会出现请求没有处理。
2、执行的路径长:一次任务的处理需要多个节点的传递,性能会降低,调试不方便。
3、执行的路径长:一次任务的处理需要多个节点的传递,性能会降低,调试不方便。
5、状态模式(和策略模式是双胞胎,出生时才分开)
定义:通过改变对象内部的状态来帮助对象控制自己的行为,状态模式允许对象在内部状态改变时改变她的行为,对象看起来好像修改它的类
从用户的视角看,如果你使用的对象能够完全改变它的行为,那么你会觉得这个对象实际上是从别的类实例化来的,然而,实际上你知道我们是在使用组合通过简单的引用不同的状态对象来造成类改变的假象
优点:结构清晰,避免了程序的复杂,提高了系统可维护性;体现了开闭原则和单一职责原则,每个状态都是一个子类,与单一职责原则高度符合,扩展状态只需增加子类,正是开闭原则的体现。
缺点:如果一个事务有很多个状态,就会造成子类太多的问题。需要在项目使用时来衡量是否使用状态模式。
5、访问者
7、中介者
8、备忘录
9、命令模式
10、解释器
11、迭代器模式

浙公网安备 33010602011771号