1.C++队列queue用法详解
2.deque用法详解
Lists将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢。(支持迭代器,用法和vectors基本 一样) assign() 给list赋值 back() 返回最后一个元素 begin() 返回指向第一个元素的迭代器 clear() 删除所有元素 empty() 如果list是空的则返回true end() 返回末尾的迭代器 erase() 删除一个元素 front() 返回第一个元素 get_allocator() 返回list的配置器 insert() 插入一个元素到list中 max_size() 返回list能容纳的最大元素数量 merge() 合并两个list pop_back() 删除最后一个元素 pop_front() 删除第一个元素 push_back() 在list的末尾添加一个元素 push_front() 在list的头部添加一个元素 rbegin() 返回指向第一个元素的逆向迭代器 remove() 从list删除元素 remove_if() 按指定条件删除元素 rend() 指向list末尾的逆向迭代器 resize() 改变list的大小 reverse() 把list的元素倒转 size() 返回list中的元素个数 sort() 给list排序 splice() 合并两个list swap() 交换两个list unique() 删除list中重复的元素3、函数名前后加加const
1.首先要注意只有类的成员函数才能在函数名后面加上const,这时成员函数叫做常量成员函数。
2.常量成员函数在执行期间不能修改成员变量的值(静态成员变量除外),也不能调用同类的非常量成员函数(同样的静态成员函数除外)
3.而在函数名前加const则表示函数的返回值为常量。
4.用法如下:
class Sample {
public:
int value;
void GetValue() const;
void func() {};
Sample() { value = 0; }
};
void Sample::GetValue() const {
//value = 0;//错误,常量成员函数不能修改成员变量的值
//func();//错误,常量成员函数不能调用非常量成员函数
}
int main(void)
{
const Sample s;//常量对象
//s.value = 1;//错误,常量对象不能被修改
int i = s.value;//虽然不能修改,但能获取其值
//s.func();//错误,常量对象上面不能执行非常量成员函数,即使这个成员函数为空
s.GetValue();//真确,常量对象上面可以执行常量函数
Sample s1; //非常量对象
s1.GetValue();//非常量对象可以调用常量成员函数
return 0;
}
2、constexpr关键字
1、constexpr函数指的是在编译的时候就能得到其返回值的函数,也就是说编译器将constexpr函数直接转换成其返回值,因此,constexpr函数都是被隐式地定义为内联函数。使用constexpr关键字来修饰constexpr函数。对于变量,constexpr关键字会检测后面的是不是常量表达式,不是的话就会报错,如果用const就只能自己判断了,反正都不会报错。(提前编译可以节省运行时间?)
2、constexpr使用
1.情况1
constexpr int myFunc(int i) //形参可以是非常量的
{
return i; //函数里只能有一条语句return,constexpr函数的返回值类型必须是字面值类型
}
constexpr int i = myFunc(1) * 4; //实参必须是常量
2.情况2
int i = 10;
constexpr int x = 10 * i;//会报错,因为i不是常量
3.情况3
int i = 10;
const int x = 10 * i; //不会报错
1、纯虚函数(外部抽象类接口)
1、C++没有接口类,它通过使用纯虚函数来生成抽象类。抽象类可以作为接口的集合,实现了接口类的功能。C++中含有纯虚函数的类叫做抽象类,顾名思义,它本身就是行为抽象的集合,因此它只描述了有这个行为,但是并未描述行为的具体做
法,具体的做法在派生类中去实现,不同的派生类有不同的实现。
2、虚函数定义
class 类名
{
virtual 函数返回值类型 函数名 (参数列表) = 0; //即,抽象类不去实现函数体
};
注:
Ⅰ实际上C++允许抽象类实现函数体,但是做为抽象类的人应当遵循所有子类都有的行为才可以在抽象类中实现。否则这与抽象类的设计理念相违背。
Ⅱ抽象类不能被实例化,因为大多数时候的抽象类的纯虚函数都没有相应的实现。
Ⅲ由于基类的指针(引用)可以使用子类的函数,这样,我们通过抽象类的指针可以去调用派生类对象的函数。
Ⅳ通过多态,基类指针可以访问子类的函数。
3、用法
#include一、设计模式 1、设计模式constexpr double PI = 3.1415926; using std::endl; using std::cout; class Figure //抽象类 { public: //定义纯虚函数 virtual double getArea() const = 0 //获取面积 { cout << "Hello World" << endl; //实际上C++允许我们在抽象类中实现纯虚函数的函数体 return 0; } virtual double getCircum() const = 0; //获取周长 }; class Rect : public Figure { public: Rect(double a, double b); virtual double getArea()const { Figure::getArea(); //由于抽象类不能实例化,只能这样在派生类中调用。不能在类外调用 return a * b; } virtual double getCircum()const { return 2 * (a + b); } private: double a; double b; }; Rect::Rect(double a, double b) { this->a = a; this->b = b; } class Triangle : public Figure { public: Triangle(double a, double b, double c); virtual double getArea()const { //利用海伦公式计算三角形面积 double p = (a + b + c) / 2; double tmp = p * (p - a) * (p - b) * (p - c); return pow(tmp, 0.5); } virtual double getCircum()const { return a + b + c; } private: double a; double b; double c; }; Triangle::Triangle(double a, double b, double c) { this->a = a; this->b = b; this->c = c; } class Circle : public Figure { public: Circle(double r); virtual double getArea()const { return PI * r * r; } virtual double getCircum()const { return 2 * PI * r; } private: double r; }; Circle::Circle(double r) { this->r = r; } int main() { //Figure f; ---->error,抽象类不能实例化对象。 Figure* p_rect = new Rect(4, 6); Figure* p_triangle = new Triangle(3, 3, 3); Figure* p_circle = new Circle(10); cout << "矩形面积:" << p_rect->getArea() << " 矩形周长:" << p_rect->getCircum() << endl; cout << "三角形面积:" << p_triangle->getArea() << " 三角形周长:" << p_triangle->getCircum() << endl; cout << "圆形面积:" << p_circle->getArea() << " 圆形周长:" << p_circle->getCircum() << endl; return 0; }
23种设计模式汇总
1.设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临 的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。 设计模式的用途 2.使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式在软件开发中的用途主要有: Ⅰ开发人员的共同平台:提供了一个标准的术语系统,且具体到特定的情景。例如,单例设计模式意味着使用单个对象,这样所有熟悉单例设计模式的开 发人员都能使用单个对象,并且可以通过这种方式告诉对方,程序使用的是单例模式。 Ⅱ最佳的实践:设计模式已经经历了很长一段时间的发展,它们提供了软件开发过程中面临的一般问题的最佳解决方案。学习这些模式有助于经验不足的 开发人员通过一种简单快捷的方式来学习软件设计。 3.设计模式的类型:设计模式总共有 23 种。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。2、AbstactFactory 模式(抽象工厂模式)
抽象工厂结构
假如我们要买水果,水果的产地来自中国、日本、美国,每个国家的水果种类都可以分为苹果、香蕉、梨子。作为开发者,我们就不得不创建苹果类(香 蕉和梨子类似),然后每种苹果都继承自苹果类。每上架一个国家的苹果我们都要实现一次苹果类,这样就会有成千上万的苹果类需要被创建, AbstractFactory 模式就是用来解决这类问题的:要创建一组相关或者相互依赖的对象。 注: 1.也就是外部抽象接口只有抽象工厂类,而抽象工厂内有返回指针是苹果、香蕉、梨子的纯虚函数。 2.所以既然每个国家都有苹果、香蕉、梨子,那么我们可以为每个国家创建一个继承抽象工厂的国家工厂类,而这个国家工厂里有苹果、香蕉、梨子的多 态实例化虚函数。 3.对于文3中“每上架一个国家的苹果我们都要实现一次苹果类,这样就会有成千上万的苹果类需要被创建”,对于这句话,首先要说明的是每个国家的苹 果都必须创建一个苹果类并继承基类苹果(其他说明同理),从这里就可以看出,如果我们想从主程序里使用许多国家的苹果,那么我们就地创建许多国 家的苹果对象,这并不是对象复用的本质。所以这些基类的国家苹果等水果类就可以放到国家工厂里统一管理。最后我们就可以通过抽象工厂获取国家工 厂,从而获取国家的各种水果。 4.AbstractFactory 模式和 Factory模式的区别是初学(使用)设计模式时候的一个容易引起困惑的地方。实际上,AbstractFactory模式是为创建 一组(有多类)相关或依赖的对象提供创建接口,而 Factory模式是为一类对象提供创建接口或延迟对象的创建到子类中实现。并且可以看到, AbstractFactory模式通常都是使用 Factory 模式实现。
相关用法 //抽象工厂模式 #include3、Factory 模式(工厂模式)using namespace std; //----------------------------------------------------------------------------------------- //苹果的抽象 class AbstractApple { public: virtual void showName() = 0; }; //中国苹果 class ChinaApple :public AbstractApple { public: virtual void showName() { cout << "中国苹果" << endl; } }; //美国苹果 class USAApple :public AbstractApple { public: virtual void showName() { cout << "美国苹果" << endl; } }; //日本苹果 class JapanApple :public AbstractApple { public: virtual void showName() { cout << "日本苹果" << endl; } }; //----------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- //香蕉的抽象 class AbstractBanana { public: virtual void showName() = 0; }; //中国香蕉 class ChinaBanana :public AbstractBanana { public: virtual void showName() { cout << "中国香蕉" << endl; } }; //美国香蕉 class USABanana :public AbstractBanana { public: virtual void showName() { cout << "美国香蕉" << endl; } }; //日本香蕉 class JapanBanana :public AbstractBanana { public: virtual void showName() { cout << "日本香蕉" << endl; } }; //----------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- //鸭梨的抽象 class AbstractPear { public: virtual void showName() = 0; }; //中国鸭梨 class ChinaPear :public AbstractPear { public: virtual void showName() { cout << "中国鸭梨" << endl; } }; //美国鸭梨 class USAPear :public AbstractPear { public: virtual void showName() { cout << "美国鸭梨" << endl; } }; //日本鸭梨 class JapanPear :public AbstractPear { public: virtual void showName() { cout << "日本鸭梨" << endl; } }; //----------------------------------------------------------------------------------------- //抽象工厂 针对产品族 class AbstractFactory { public: virtual AbstractApple* CreateApple() = 0; virtual AbstractBanana* CreateBanana() = 0; virtual AbstractPear* CreatePear() = 0; }; //中国工厂 class ChinaFactory :public AbstractFactory { virtual AbstractApple* CreateApple() { return new ChinaApple; } virtual AbstractBanana* CreateBanana() { return new ChinaBanana; } virtual AbstractPear* CreatePear() { return new ChinaPear; } }; //美国工厂 class USAFactory :public AbstractFactory { virtual AbstractApple* CreateApple() { return new USAApple; } virtual AbstractBanana* CreateBanana() { return new USABanana; } virtual AbstractPear* CreatePear() { return new USAPear; } }; //日本工厂 class JapanFactory :public AbstractFactory { virtual AbstractApple* CreateApple() { return new JapanApple; } virtual AbstractBanana* CreateBanana() { return new JapanBanana; } virtual AbstractPear* CreatePear() { return new JapanPear; } }; int main() { AbstractFactory* factory = NULL; AbstractApple* apple = NULL; AbstractBanana* Banana = NULL; AbstractPear* Pear = NULL; //中国工厂 factory = new ChinaFactory; //我们只需要改变这里,就获取其他国家水果信息。 apple = factory->CreateApple(); Banana = factory->CreateBanana(); Pear = factory->CreatePear(); apple->showName(); Banana->showName(); Pear->showName(); delete Pear; delete apple; delete Banana; delete factory; }
工厂模式结构(工厂接口获取中国工厂,产品接口通过工厂接口获取中国产品)
在面向对象系统设计中经常可以遇到以下的两类问题: 我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。 所以就不得不在要用到子类的地方写new 对象。这样实体类的使用者必须知道实际的子类名称,以及会使程序的扩展性和维护变得越来越困难。 还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。只能在父类中写方法调用,具体调用哪一个类的方法交给子类实现。 以上两个问题也就引出了 Factory 模式的两个最重要的功能: Ⅰ定义创建对象的接口,封装了对象的创建。 Ⅱ使得具体化类的工作延迟到了子类中。 注: 1.上面索说的就是当我们希望在主程序里调用一个共有的函数名字来执行某个子类行为,这样可以在主程序里达到了统一及简洁。 2.如果为每一个具体的 ConcreteProduct 类的实例化提供一个函数体,那么我们可能不得不在系统中添加了一个方法来处理这个新建的 ConcreteProduct 3.可以看出,Factory 模式对于对象的创建给予开发人员提供了很好的实现策略,但是Factory 模式仅仅局限于一类类(就是说Product 是一类,有 一个共同的基类),如果我们要为不同类的类提供一个对象创建的接口,那就要用 AbstractFactory 了。
相关代码
//Factory.h
#ifndef _FACTORY_H_
#define _FACTORY_H_
class Product;
class Factory;
class Factory
{
public:
virtual ~Factory() = 0;
virtual Product* CreateProduct() = 0;
protected:
Factory();
private:
};
class ConcreteFactory :public Factory
{
public:
~ConcreteFactory();
ConcreteFactory();
Product* CreateProduct();
protected:
private:
};
#endif //~_FACTORY_H_
//Factory.cpp
#include "Factory.h"
#include "Product.h"
#include
using namespace std;
Factory::Factory()
{
}
Factory::~Factory()
{
}
ConcreteFactory::ConcreteFactory()
{
cout << "ConcreteFactory....." << endl;
}
ConcreteFactory::~ConcreteFactory()
{
}
Product* ConcreteFactory::CreateProduct()
{
return new ConcreteProduct();
}
//Product.h
#ifndef _PRODUCT_H_
#define _PRODUCT_H_
class Product
{
public:
virtual ~Product() = 0;
protected:
Product();
private:
};
class ConcreteProduct :public Product
{
public:
~ConcreteProduct();
ConcreteProduct();
protected:
private:
};
#endif //~_PRODUCT_H_
//Product.cpp
#include "Product.h"
#include
using namespace std;
Product::Product()
{
}
Product::~Product()
{
}
ConcreteProduct::ConcreteProduct()
{
cout << "ConcreteProduct...." << endl;
}
ConcreteProduct::~ConcreteProduct()
{
}
//main.cpp
#include "Factory.h"
#include "Product.h"
#include
using namespace std;
int main(int argc, char* argv[])
{
Factory* fac = new ConcreteFactory();
Product* p = fac->CreateProduct();
return 0;
}
4、Singleton 模式( 单例模式)
1.Singleton 模式是设计模式中最为简单、最为常见、最容易实现,也是最应该熟悉和掌握的模式。Singleton 模式就是一个类只创建一个唯一的对 象,即一次创建多次使用。 2.实现单例模式的步骤: Ⅰ构造函数私有化 Ⅱ增加静态私有的当前类的指针变量 Ⅲ提供静态对外接口,可以让用户获得单例对象 3.单例分为懒汉式和饿汉式 懒汉式:解决了饿汉式内存浪费问题,但是线程不安全的,可以通过互斥量mutex.lock()和mutex.unlock()来解决 饿汉式:还没有使用该单例对象,该单例对象就已经被加载到内存了,在对象过多时会造成内存浪费
相关代码 #include5、Adapter 模式(适配器模式)using namespace std; //懒汉式 对象的创建在第一次调用getInstance函数时创建 //懒汉式是线程不安全的 class SingletonLazy { public: static SingletonLazy* getInstance() { if (pSingleton == NULL) { pSingleton = new SingletonLazy; } return pSingleton; } private: SingletonLazy() {} static SingletonLazy* pSingleton; }; //在类外面进行初始化 SingletonLazy* SingletonLazy::pSingleton = NULL; //饿汉式 对象在程序执行时优先创建 //饿汉式是线程安全的 class SingletonHungry { public: static SingletonHungry* getInstance() { return pSingleton; } static void freeSpace() { if (pSingleton != NULL) { delete pSingleton; } } private: SingletonHungry() {} static SingletonHungry* pSingleton; }; //以下语句将会在main函数运行前执行 SingletonHungry* SingletonHungry::pSingleton = new SingletonHungry; int main() { //SingletonLazy p5;//单例模式不允许创建对象 SingletonLazy* p1 = SingletonLazy::getInstance(); SingletonLazy* p2 = SingletonLazy::getInstance(); if (p1 == p2) { cout << "单例模式" << endl; } else { cout << "不是单例模式" << endl; } //SingletonHungry p6;//单例模式不允许创建对象 SingletonHungry* p3 = SingletonHungry::getInstance(); SingletonHungry* p4 = SingletonHungry::getInstance(); if (p3 == p4) { cout << "单例模式" << endl; } else { cout << "不是单例模式" << endl; } }
采用继承原有接口类的方式
采用组合原有接口类的方式
1.为了完成某项工作购买了一个第三方的库来加快开发。这就带来了一个问题:我们在应用程序中已经设计好了接口,与这个第三方提供的接口不一致, 为了使得这些接口不兼容的类(不能在一起工作)可以在一起工作了,Adapter 模式提供了将一个类(第三方库)的接口转化希望的接口。适配器模式分 为类模式和对象模式。 2.在 Adapter 模式的结构图中可以看到,类模式的 Adapter 采用继承的方式复用 Adaptee的接口,而在对象模式的 Adapter 中我们则采用组合的 方式实现 Adaptee 的复用。 注:当我们用内部抽象接口对象调用外部函数时,是先调用适配器同名函数,如何在适配器同名函数里调用第三方不同名函数。
只演示采用组合的方式
//Adapter.h
#ifndef _ADAPTER_H_
#define _ADAPTER_H_
class Target
{
public:
Target();
virtual ~Target();
virtual void Request();
};
class Adaptee
{
public:
Adaptee();
~Adaptee();
void SpecificRequest();
};
class Adapter:public Target
{
public:
Adapter(Adaptee* ade);
~Adapter();
void Request();
private:
Adaptee* _ade;
};
#endif //~_ADAPTER_H_
//Adapter.cpp
#include "Adapter.h"
#include
Target::Target()
{
}
Target::~Target()
{
}
void Target::Request()
{
std::cout<<"Target::Request"<
}
Adaptee::~Adaptee()
{
}
void Adaptee::SpecificRequest()
{
std::cout<<"Adaptee::SpecificRequest"<
this->_ade = ade;
}
Adapter::~Adapter()
{
}
void Adapter::Request()
{
_ade->SpecificRequest();
}
//main.cpp
#include "Adapter.h"
#include
using namespace std;
int main(int argc,char* argv[])
{
Adaptee* ade = new Adaptee;
Target* adt = new Adapter(ade);
adt->Request();
return 0;
}
6、Proxy 模式(代理模式)
1.代理模式(Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问。 代理对象在客服端和目标对象之间起到中介作用。在生活 中,我们经常见到这样的场景,如:租房中介、售票黄牛、婚介、经纪人、快递、 事务代理、非侵入式日志监听等,这些都是代理模式的实际体现 2.注意事项: Ⅰ和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 Ⅱ和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。 3.举例:现在有一个操作系统,只需要调用run()就可以启动操作系统,但是进入操作系统之前必须要进行账户名和密码的认证。认证成功后这个代理 才会让你进入操作系统,其中认证的这个过程就是一个代理。 4.
//代理模式:提供一种代理来控制其他对象的访问 #include7、Decorator 模式(装饰器模式)using namespace std; class AbstractCommonInterface { public: virtual void run() = 0; }; //下面是操作系统类 class MySystem :public AbstractCommonInterface { public: virtual void run() { cout << "系统启动" << endl; } }; //代理: 启动系统必须要权限验证,不是所以的人都可以来启动我的系统,必须要提供用户名和密码 class MySystemProxy :public AbstractCommonInterface { public: MySystemProxy(string userName, string password) { this->mUserName = userName; this->mPassword = password; pMySystem = new MySystem; } bool checkUserNameAndPassword() { if (mUserName == "admin" && mPassword == "admin") { return true; } return false; } virtual void run() { if (checkUserNameAndPassword() == true) { cout << "启动成功" << endl; this->pMySystem->run(); } else { cout << "用户名或者密码错误,权限不足" << endl; } } ~MySystemProxy() { if (pMySystem != NULL) { delete pMySystem; } } private: string mUserName; string mPassword; MySystem* pMySystem; }; int main() { MySystemProxy* proxy = new MySystemProxy("admin", "admin"); proxy->run(); }
装饰器模式结构
1.装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。 2.结构 Component(被装饰对象的基类):定义一个对象接口,可以给这些对象动态地添加职责。 ConcreteComponent(具体被装饰对象):定义一个对象,可以给这个对象添加一些职责。 Decorator(装饰者抽象类):维持一个指向Component实例的引用,并定义一个与Component接口一致的接口。 ConcreteDecorator(具体装饰者):具体的装饰对象,给内部持有的具体被装饰对象,增加具体的职责。
//装饰器模式:对类的功能进行扩展(代替继承)。可以动态的给类增加功能 //我们需要为英雄增加额外的功能或者属性,但是又不能影响Hero类,这个时候就可以考虑装饰器模式 #include8、Composite 模式(组合实体模式)(未研究)using namespace std; //抽象的英雄 class AbstractHero { public: virtual void showStatus() = 0; int mHp; int mMp; int mAt; int mDf; }; class HeroA :public AbstractHero { public: HeroA() { mHp = 0; mMp = 0; mAt = 0; mDf = 0; } virtual void showStatus() { cout << "血量:" << mHp << endl; cout << "魔法:" << mMp << endl; cout << "攻击:" << mAt << endl; cout << "防御:" << mDf << endl; } }; //英雄穿上某个装饰物,那么也还是一个英雄 class AbstractEquipment : public AbstractHero { public: AbstractEquipment(AbstractHero* hero) { this->pHero = hero; } virtual void showStatus() { } AbstractHero* pHero; }; //给英雄穿上狂徒铠甲 class KuangtuEquipment :public AbstractEquipment { public: KuangtuEquipment(AbstractHero* hero) :AbstractEquipment(hero) {} //增加额外的功能 void AddKuangtu() { cout << "英雄穿了狂徒之后" << endl; this->mHp = this->pHero->mHp; this->mMp = this->pHero->mMp; this->mAt = this->pHero->mAt; this->mDf = this->pHero->mDf + 30; } virtual void showStatus() { AddKuangtu(); cout << "血量:" << mHp << endl; cout << "魔法:" << mMp << endl; cout << "攻击:" << mAt << endl; cout << "防御:" << mDf << endl; } }; //无尽之刃 class Wujinzhireng :public AbstractEquipment { public: Wujinzhireng(AbstractHero* hero) :AbstractEquipment(hero) {} //增加额外的功能 void AddKuangtu() { cout << "英雄穿了无尽之刃后" << endl; this->mHp = this->pHero->mHp; this->mMp = this->pHero->mMp; this->mAt = this->pHero->mAt + 80; this->mDf = this->pHero->mDf; } virtual void showStatus() { AddKuangtu(); cout << "血量:" << mHp << endl; cout << "魔法:" << mMp << endl; cout << "攻击:" << mAt << endl; cout << "防御:" << mDf << endl; } }; void test01() { AbstractHero* hero = new HeroA; hero->showStatus(); cout << "-------------------" << endl; //给英雄穿上狂徒 hero = new KuangtuEquipment(hero);//这里应该是指向了抽象英雄类 hero->showStatus(); hero->mAt = 33; cout << "-------------------" << endl; //给英雄装备武器 hero = new Wujinzhireng(hero); //这里应该是指向了抽象英雄类 hero->showStatus(); } int main() { test01(); }
组合实体模式结构
1.将对象组合成树形结构以表示“部分-整体”的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性。 2.注:主要是对单个对象及组合对象的使用。
//Composite.h #ifndef COMPOSITE_H #define COMPOSITE_H #include9、Template 模式(模板模式)// 组合中的抽象基类 class Component { public: Component() {} virtual ~Component() {} // 纯虚函数,只提供接口,没有默认的实现 virtual void Operation() = 0; // 虚函数,提供接口,有默认的实现就是什么都不做 virtual void Add(Component* pChild); virtual void Remove(Component* pChild); virtual Component* GetChild(int nIndex); }; // 派生自 Component,是其中的叶子组件的基类 class Leaf: public Component { public: Leaf() {} virtual ~Leaf() {} virtual void Operation(); }; // 派生自 Component,是其中的含有子件的组件的基类 class Composite: public Component { public: Composite() {} virtual ~Composite(); virtual void Operation(); virtual void Add(Component* pChild); virtual void Remove(Component* pChild); virtual Component* GetChild(int nIndex); private: // 采用 list 容器去保存子组件 std::list
m_ListOfComponent; }; #endif //Composite.cpp #include "Composite.h" #include #include void Component::Add(Component* pChild) { } void Component::Remove(Component* pChild) { } Component* Component::GetChild(int nIndex) { return NULL; } void Leaf::Operation() { std::cout << "Operation by leafn"; } Composite::~Composite() { std::list ::iterator iter1, iter2, temp; for (iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();iter1 != iter2;) { temp = iter1; ++iter1; delete (*temp); } } void Composite::Add(Component* pChild) { m_ListOfComponent.push_back(pChild); } void Composite::Remove(Component* pChild) { std::list ::iterator iter; iter = find(m_ListOfComponent.begin(), m_ListOfComponent.end(), pChild); if (m_ListOfComponent.end() != iter) { m_ListOfComponent.erase(iter); } } Component* Composite::GetChild(int nIndex) { if (nIndex <= 0 || nIndex > m_ListOfComponent.size()) return NULL; std::list ::iterator iter1, iter2; int i; for (i = 1, iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();iter1 != iter2;++iter1, ++i) { if (i == nIndex) break; } return *iter1; } void Composite::Operation() { std::cout << "Operation by Compositen"; std::list ::iterator iter1, iter2; for (iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();iter1 != iter2;++iter1) { (*iter1)->Operation(); } } //main.cpp #include "Composite.h" #include #include int main() { Leaf* pLeaf1 = new Leaf(); Leaf* pLeaf2 = new Leaf(); Composite* pComposite = new Composite; pComposite->Add(pLeaf1); pComposite->Add(pLeaf2); pComposite->Operation(); std::cout << "--------------------------" << std::endl; pComposite->GetChild(2)->Operation(); delete pComposite; }
模板模式
1.在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现)在不同的对象中有不同的细节实现,但是逻辑(算 法)的框架(或通用的应用算法)是相同的。Template 提供了这种情况的一个实现框架。Template 模式是采用继承的方式实现这一点:将逻辑(算 法)框架放在抽象基类中,并定义好细节的接口,子类中实现细节。 2.假如我们要做饮料,那么我们首先会定义一个做饮料的模板,即煮水->冲泡->导入杯中->加辅助材料,具体煮什么水、冲泡什么东西放到子类中实现。 然后定义一个模板方法,当我们要做饮料时就调用这个方法即可。 3.可以看到Template模式获得一种反向控制结构效果,这也是面向对象系统的分析和设计中一个原则,依赖倒置原则。其含义就是父类调用子类的操作 (高层模块调用低层模块的操作),低层模块实现高层模块声明的接口。这样控制权在父类(高层模块),低层模块反而要依赖高层模块。 4.但是也有局限性,因为模板模式采用继承这种强制约束关系,导致复用性不高。假如我接下来要做冷饮,那么Make函数中的煮水操作其实可以省去直 接冲泡即可,但是我们就无法再次使用这个模板了,这样就导致了不能复用子类的实现步骤。
//模板方法模式:在父类中定义一个方法的抽象,由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中的执行次序。 #include10、Strategy 模式(策略模式)using namespace std; //做饮料模板 class DrinkTemplate { public: //煮水 virtual void BoildWater() = 0; //冲泡 virtual void Brew() = 0; //倒入杯中 virtual void PourInCup() = 0; //加辅助材料 virtual void AddSomething() = 0; //模板方法 void Make() { BoildWater(); Brew(); PourInCup(); AddSomething(); } }; //做咖啡: 实现做饮料模板 class Coffee :public DrinkTemplate { virtual void BoildWater() { cout << "煮山泉水" << endl; } virtual void Brew() { cout << "冲泡咖啡" << endl; } virtual void PourInCup() { cout << "咖啡倒入杯中" << endl; } virtual void AddSomething() { cout << "加糖,加牛奶" << endl; } }; //做茶: 实现做饮料模板 class Tea :public DrinkTemplate { virtual void BoildWater() { cout << "煮自来水" << endl; } virtual void Brew() { cout << "冲泡铁观音" << endl; } virtual void PourInCup() { cout << "茶水倒入杯中" << endl; } virtual void AddSomething() { cout << "加糖,加大蒜" << endl; } }; void test01() { Tea* tea = new Tea; tea->Make(); cout << "-------------------"< Make(); } int main() { test01(); }
策略模式结构
1.Strategy 模式和 Template 模式要解决的问题是相同(类似)的,都是为了给业务逻辑(算法)具体实现和抽象接口之间的解耦。 2.简而言之,Strategy 模式是对算法的封装。处理一个问题的时候可能有多种算法,这些算法的接口(输入参数,输出参数等)都是一致的,那么可以考虑 采用Strategy 模式对这些算法进行封装,在基类中定义一个函数接口就可以了。 3.举例:假如现在有个英雄需要使用武器对付敌人,武器有两种匕首和AK,那么这么选择使用哪吧武器其实就是一种策略了那么就可以将策略模式分为三 部分: ⅠStrategy 策略基类 (抽象武器) ⅡConcreteStrategy 具体策略 (使用匕首或AK) ⅢContext 具体使用策略的对象(英雄) 4.总结:可以看到Character 类是通过组合WeaponStrategy 的形式调用武器使用的,这就比继承要好得多,因为在面向对象的设计中的有一条很重要 的原则就是:优先使用对象组合,而非类继承。 5.优点: Ⅰ算法可以自由切换。 Ⅱ避免使用多重条件判断。 Ⅲ扩展性良好。 6.缺点: Ⅰ策略类会增多。 Ⅱ所有策略类都需要对外暴露
//策略模式 #include11、Observer 模式(观察者模式)using namespace std; //抽象武器 策略基类(抽象的策略) class WeaponStrategy { public: virtual void UseWeapon() = 0; }; //具体的策略使用匕首作为武器 class Knife :public WeaponStrategy { public: virtual void UseWeapon() { cout << "使用匕首" << endl; } }; //具体的策略使用AK47作为武器 class AK47 :public WeaponStrategy { public: virtual void UseWeapon() { cout << "使用AK47" << endl; } }; //具体使用策略的角色 class Character { public: WeaponStrategy* pWeapon; void setWeapon(WeaponStrategy* pWeapon) { this->pWeapon = pWeapon; } void ThrowWeapon() { this->pWeapon->UseWeapon(); } }; void test01() { Character* character = new Character; WeaponStrategy* knife = new Knife; WeaponStrategy* ak47 = new AK47; //用匕首当作武器 character->setWeapon(knife); character->ThrowWeapon(); character->setWeapon(ak47); character->ThrowWeapon(); delete ak47; delete knife; delete character; } int main() { test01(); }
观察者模式结构
1.Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同 步改变。最常见的一个例子就是:对同一组数据进行统计分析时候,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百 分比统计显示等)。指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 2.举例:Subject 提供依赖于它的观察者 Observer 的注册(registerObserver)和注销(remove)操作,并且提供了使得依赖于它的所有观察者 同步的操作(notifyObserver),观察者 Observer 则提供一个 Update 操作,注意这里的 Observer 的 Update 操作并不在 Observer 改变了 Subject 目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有Observer 进行修改(调用 Update)。 3.优点: Ⅰ观察者和被观察者是抽象耦合的。 Ⅱ建立一套触发机制。 4.缺点: Ⅰ如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 Ⅱ观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
#include12、Command 模式(命令模式)#include using namespace std; //抽象的英雄 抽象的观察者 Observer class AbstractHero { public: virtual void Update() = 0; }; //具体的英雄 具体的观察者 class HeroA :public AbstractHero { public: HeroA() { cout << "英雄A正在鲁BOSS" << endl; } virtual void Update() { cout << "英雄A停止撸,待机状态" << endl; } }; class HeroB :public AbstractHero { public: HeroB() { cout << "英雄B正在鲁BOSS" << endl; } virtual void Update() { cout << "英雄B停止撸,待机状态" << endl; } }; class HeroC :public AbstractHero { public: HeroC() { cout << "英雄C正在鲁BOSS" << endl; } virtual void Update() { cout << "英雄C停止撸,待机状态" << endl; } }; class HeroD :public AbstractHero { public: HeroD() { cout << "英雄D正在鲁BOSS" << endl; } virtual void Update() { cout << "英雄D停止撸,待机状态" << endl; } }; class HeroE :public AbstractHero { public: HeroE() { cout << "英雄E正在鲁BOSS" << endl; } virtual void Update() { cout << "英雄E停止撸,待机状态" << endl; } }; //定义抽象的观察目标 Subject class AbstractBoss { public: // 添加观察者 virtual void addHero(AbstractHero* hero) = 0; // 删除观察者 virtual void deleteHero(AbstractHero* hero) = 0; // 通知所有观察者 virtual void notifv() = 0; }; //相对于 concreteSubject class BOSSA :public AbstractBoss { public: // 添加观察者 virtual void addHero(AbstractHero* hero) { pHeroList.push_back(hero); } // 删除观察者 virtual void deleteHero(AbstractHero* hero) { pHeroList.remove(hero); } // 通知所有观察者 virtual void notifv() { for (list
::iterator it = pHeroList.begin(); it != pHeroList.end(); it++) { (*it)->Update(); } } list pHeroList; }; void test01() { // 创建观察者 AbstractHero* heroA = new HeroA; AbstractHero* heroB = new HeroB; AbstractHero* heroC = new HeroC; AbstractHero* heroD = new HeroD; AbstractHero* heroE = new HeroE; // 创建观察目标 AbstractBoss* bossA = new BOSSA; bossA->addHero(heroA); bossA->addHero(heroB); bossA->addHero(heroC); bossA->addHero(heroD); bossA->addHero(heroE); cout << "heroC阵亡" << endl; bossA->deleteHero(heroC); cout << "Boss死了,通知其他英雄停止攻击。。。" << endl; bossA->notifv(); } int main() { test01(); return 0; }
命令模式结构
1.请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。 Command 模式的最终目的就是将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。 2.结构 Invoker 是调用者角色 Command 是命令角色,需要执行的所有命令都在这里 Receiver 是接受者角色,知道如何实施和执行一个请求相关的操作 ConcreteCommand 将接受者对象与一个动作绑定,调用接受者相应的操作 3.假如现在有一个游戏服务器,该游戏服务器一共可以处理四种不同的请求:处理增加金币、处理增加钻石、处理玩家装备、玩家升级请求。我们需要把 这些请求封装成对象,从而加入请求队列一次进行处理。
//命令模式 #include13、Iterator 模式(迭代器模式)#include #include using namespace std; //协议处理类 (请求类) class HandleClinetProtocal { public: //处理增加金币 void AddMoney() { cout << "给玩家增加金币" << endl; } //处理增加钻石 void AddDiamond() { cout << "给玩家增加钻石" << endl; } //处理玩家装备 void AddEquipment() { cout << "给玩家穿装备" << endl; } //玩家升级 void AddLevel() { cout << "给玩家升级" << endl; } }; //命令接口 class AbstractCommand { public: //相当于execute() virtual void handle() = 0; }; //下面是把每个功能都封装为一个请求对象 //处理增加金币请求 class AddMoneyCommand:public AbstractCommand { public: AddMoneyCommand(HandleClinetProtocal* protocal) { this->pProtocol = protocal; } virtual void handle() { this->pProtocol->AddMoney(); } public: HandleClinetProtocal* pProtocol; }; //处理增加钻石请求 class AddDiamondCommand :public AbstractCommand { public: AddDiamondCommand(HandleClinetProtocal* protocal) { this->pProtocol = protocal; } virtual void handle() { this->pProtocol->AddDiamond(); } public: HandleClinetProtocal* pProtocol; }; //处理玩家装备请求 class AddEquipmentCommand :public AbstractCommand { public: AddEquipmentCommand(HandleClinetProtocal* protocal) { this->pProtocol = protocal; } virtual void handle() { this->pProtocol->AddEquipment(); } public: HandleClinetProtocal* pProtocol; }; //处理玩家升级请求 class AddLevelCommand :public AbstractCommand { public: AddLevelCommand(HandleClinetProtocal* protocal) { this->pProtocol = protocal; } virtual void handle() { this->pProtocol->AddLevel(); } public: HandleClinetProtocal* pProtocol; }; //服务器程序 (命令调用类) class Server { public: //将请求对象放入处理队列 void addRequest(AbstractCommand* command) { mCommands.push(command); } //启动处理程序 void startHandle() { while (!mCommands.empty()) { Sleep(2000); AbstractCommand* command = mCommands.front(); command->handle(); mCommands.pop(); } } queue mCommands; }; void test01() { HandleClinetProtocal* protocal = new HandleClinetProtocal; //客户端增加金币的请求 AbstractCommand* addmoney = new AddMoneyCommand(protocal); //客户端增加钻石的请求 AbstractCommand* adddiamond = new AddDiamondCommand(protocal); //客户端穿装备的请求 AbstractCommand* addequipment = new AddEquipmentCommand(protocal); //客户端升级请求 AbstractCommand* addlevel = new AddLevelCommand(protocal); //将客户端的请求加入到请求队列中 Server* server = new Server; server->addRequest(addmoney); server->addRequest(adddiamond); server->addRequest(addequipment); server->addRequest(addlevel); //服务器开始处理请求 server->startHandle(); } int main() { test01(); return 0; }
迭代器模式结构
1.迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。而且不管 这些对象是什么都需要遍历的时候,就应该选择使用迭代器模式 2.总结: Ⅰ提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。 Ⅱ隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。 Ⅲ提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍 历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。 Ⅳ当要展示一组相似对象,或者遍历一组相同对象时使用, 适合使用迭代器模式
#include14、参考资料#include #include using namespace std; //迭代抽象类,用于定义得到开始对象、得到下一个对象、判断是否到结尾、当前对象等抽象方法,统一接口 class Iterator { public: Iterator() {}; virtual ~Iterator() {}; virtual string First() = 0; virtual string Next() = 0; virtual string CurrentItem() = 0; virtual bool IsDone() = 0; }; //聚集抽象类 class Aggregate { public: virtual int Count() = 0; virtual void Push(const string& strValue) = 0; virtual string Pop(const int nIndex) = 0; virtual Iterator* CreateIterator() = 0; }; //具体迭代器类,继承Iterator 实现开始、下一个、是否结尾、当前对象等方法 class ConcreteIterator : public Iterator { public: ConcreteIterator(Aggregate* pAggregate) :m_nCurrent(0), Iterator() { m_Aggregate = pAggregate; } string First() { return m_Aggregate->Pop(0); } string Next() { string strRet; m_nCurrent++; if (m_nCurrent < m_Aggregate->Count()) { strRet = m_Aggregate->Pop(m_nCurrent); } return strRet; } string CurrentItem() { return m_Aggregate->Pop(m_nCurrent); } bool IsDone() { return ((m_nCurrent >= m_Aggregate->Count()) ? true : false); } private: Aggregate* m_Aggregate; int m_nCurrent; }; //具体聚集类 继承 class ConcreteAggregate : public Aggregate { public: ConcreteAggregate() :m_pIterator(NULL) { m_vecItems.clear(); } ~ConcreteAggregate() { if (NULL != m_pIterator) { delete m_pIterator; m_pIterator = NULL; } } Iterator* CreateIterator() { if (NULL == m_pIterator) { m_pIterator = new ConcreteIterator(this); } return m_pIterator; } int Count() { return m_vecItems.size(); } void Push(const string& strValue) { m_vecItems.push_back(strValue); } string Pop(const int nIndex) { string strRet; if (nIndex < Count()) { strRet = m_vecItems[nIndex]; } return strRet; } private: vector m_vecItems; Iterator* m_pIterator; }; int main() { ConcreteAggregate* pName = NULL; pName = new ConcreteAggregate(); if (NULL != pName) { pName->Push("hello"); pName->Push("word"); pName->Push("cxue"); } Iterator* iter = NULL; iter = pName->CreateIterator(); if (NULL != iter) { string strItem = iter->First(); while (!iter->IsDone()) { cout << iter->CurrentItem() << " is ok" << endl; iter->Next(); } } system("pause"); return 0; }
C++设计模式(全23种)



