表格网站源码,google全球推广,阳江网红桥定位,室内设计欣赏网站目录
0 、设计模式简介
一、单例模式
二、工厂模式
三、适配器模式
四、装饰器模式 0 、设计模式简介
设计模式可以分为以下三种: 创建型模式#xff1a;用来描述 “如何创建对象”#xff0c;它的主要特点是 “将对象的创建和使用分离”。包括单例、原型、工厂方法、…目录
0 、设计模式简介
一、单例模式
二、工厂模式
三、适配器模式
四、装饰器模式 0 、设计模式简介
设计模式可以分为以下三种: 创建型模式用来描述 “如何创建对象”它的主要特点是 “将对象的创建和使用分离”。包括单例、原型、工厂方法、抽象工厂和建造者 5 种模式。结构型模式用来描述如何将类或对象按照某种布局组成更大的结构。包括代理、适配器、桥接、装饰、外观、享元和组合 7 种模式。行为型模式用来识别对象之间的常用交流模式以及如何分配职责。包括模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录和解释器 11 种模式。
下面将介绍单例模式、工厂模式、适配器模式、组合模式。
一、单例模式
单例模式的实现需要三个必要的条件
单例类的构造函数必须是私有的这样才能将类的创建权控制在类的内部从而使得类的外部不能创建类的实例。单例类通过一个私有的静态变量来存储其唯一实例。单例类通过提供一个公开的静态方法使得外部使用者可以访问类的唯一实例。 注意 因为单例类的构造函数是私有的所以单例类不能被继承。 另外实现单例类时还需要考虑三个问题
创建单例对象时是否线程安全。单例对象的创建是否延时加载。获取单例对象时是否需要加锁锁会导致低性能。
单例模式分为两种饿汉方式和懒汉方式 饿汉方式在类加载的时候就实例化对象懒汉方式只有在使用的时候才初始化对象。
饿汉式单例优缺点
优点 单例对象的创建是线程安全的获取单例对象时不需要加锁。即不用考虑线程安全问题不需要加锁执行效率较高。缺点 单例对象的创建不是延时加载。类加载的时候就初始化不管后期用不用都占着空间浪费了内存
懒汉式单例优缺点
优点 对象的创建是线程安全的。支持延时加载。缺点获取对象的操作被加上了锁影响了并发度。 如果单例对象需要频繁使用那这个缺点就是无法接受的。如果单例对象不需要频繁使用那这个缺点也无伤大雅。
使用场景
饿汉式单例模式在类加载时就创建实例适用于单例对象的创建频繁的场景以及对于性能要求较高的场景。懒汉式单例模式在第一次被使用时创建实例适用于单例对象的创建不是很频繁的场景。
饿汉方式代码
class singleton{protected:singleton(){}private:static singleton* p;public:static singleton* initance();};singleton* singleton::p new singleton;singleton* singleton::initance(){return p;}
懒汉方式代码
class singleton
{
protected:singleton(){pthread_mutex_init(mutex);}
private:static singleton* p;
public:static pthread_mutex_t mutex;static singleton* initance();
};pthread_mutex_t singleton::mutex;
singleton* singleton::p NULL;
singleton* singleton::initance()
{if (p NULL){pthread_mutex_lock(mutex);if (p NULL)p new singleton();pthread_mutex_unlock(mutex);}return p;
}
二、工厂模式
工厂模式分为简单工厂模式、工厂方法模式、抽象工厂模式。
简单工厂模式提供一个工厂类在这个工厂类中生产A、B、C类产品。
工厂方法模式提供n个工厂类都继承自同一个总工厂类然后分别生产各自的产品。
抽象工厂模式提供n个工厂类都继承自同一个总工厂类然后分别生产各自的产品产品可以包含多种。也就是对于每一个工厂有多条生产线。 1.简单工厂模式 NiKeShoes、AdidasShoes、LiNingShoes为具体鞋子的类分别是耐克、阿迪达斯和李宁鞋牌的鞋它们都继承于Shoes抽象类。
// 鞋子抽象类
class Shoes
{
public:virtual ~Shoes() {}virtual void Show() 0;
};// 耐克鞋子
class NiKeShoes : public Shoes
{
public:void Show(){std::cout 我是耐克球鞋我的广告语Just do it std::endl;}
};// 阿迪达斯鞋子
class AdidasShoes : public Shoes
{
public:void Show(){std::cout 我是阿迪达斯球鞋我的广告语:Impossible is nothing std::endl;}
};// 李宁鞋子
class LiNingShoes : public Shoes
{
public:void Show(){std::cout 我是李宁球鞋我的广告语Everything is possible std::endl;}
};
ShoesFactory为工厂类类里实现根据鞋子类型创建对应鞋子产品对象的CreateShoes(SHOES_TYPE type)函数。
enum SHOES_TYPE
{NIKE,LINING,ADIDAS
};// 总鞋厂
class ShoesFactory
{
public:// 根据鞋子类型创建对应的鞋子对象Shoes *CreateShoes(SHOES_TYPE type){switch (type){case NIKE:return new NiKeShoes();break;case LINING:return new LiNingShoes();break;case ADIDAS:return new AdidasShoes();break;default:return NULL;break;}}
}; main函数先是构造了工厂对象后创建指定类型的具体鞋子产品对象创建了具体鞋子产品的对象便可直接打印广告。因为采用的是new的方式创建了对象用完了要通过delete 释放资源资源。
int main()
{// 构造工厂对象ShoesFactory shoesFactory;// 从鞋工厂对象创建阿迪达斯鞋对象Shoes *pNikeShoes shoesFactory.CreateShoes(NIKE);if (pNikeShoes ! NULL){// 耐克球鞋广告喊起pNikeShoes-Show();// 释放资源delete pNikeShoes;pNikeShoes NULL;}// 从鞋工厂对象创建阿迪达斯鞋对象Shoes *pLiNingShoes shoesFactory.CreateShoes(LINING);if (pLiNingShoes ! NULL){// 李宁球鞋广告喊起pLiNingShoes-Show();// 释放资源delete pLiNingShoes;pLiNingShoes NULL;}// 从鞋工厂对象创建阿迪达斯鞋对象Shoes *pAdidasShoes shoesFactory.CreateShoes(ADIDAS);if (pAdidasShoes ! NULL){// 阿迪达斯球鞋广告喊起pAdidasShoes-Show();// 释放资源delete pAdidasShoes;pAdidasShoes NULL;}return 0;
}
输出结果 2.工厂方法模式 有的地方直接是抽象工厂模式即对工厂也进行了抽象 ShoesFactory抽象工厂类提供了创建具体鞋子产品的纯虚函数。
NiKeProducer、AdidasProducer、LiNingProducer具体工厂类继承持续工厂类实现对应具体鞋子产品对象的创建。
// 总鞋厂
class ShoesFactory
{
public:virtual Shoes *CreateShoes() 0;virtual ~ShoesFactory() {}
};// 耐克生产者/生产链
class NiKeProducer : public ShoesFactory
{
public:Shoes *CreateShoes(){return new NiKeShoes();}
};// 阿迪达斯生产者/生产链
class AdidasProducer : public ShoesFactory
{
public:Shoes *CreateShoes(){return new AdidasShoes();}
};// 李宁生产者/生产链
class LiNingProducer : public ShoesFactory
{
public:Shoes *CreateShoes(){return new LiNingShoes();}
};
main函数针对每种类型的鞋子构造了每种类型的生产线再由每个生产线生产出对应的鞋子。需注意的是具体工厂对象和具体产品对象用完了需要通过delete释放资源。
int main()
{// 生产耐克流程 //// 鞋厂开设耐克生产线ShoesFactory *niKeProducer new NiKeProducer();// 耐克生产线产出球鞋Shoes *nikeShoes niKeProducer-CreateShoes();// 耐克球鞋广告喊起nikeShoes-Show();// 释放资源delete nikeShoes;delete niKeProducer;// 生产阿迪达斯流程 //// 鞋厂开设阿迪达斯生产者ShoesFactory *adidasProducer new AdidasProducer();// 阿迪达斯生产线产出球鞋Shoes *adidasShoes adidasProducer-CreateShoes();// 阿迪达斯球鞋广喊起adidasShoes-Show();// 释放资源delete adidasShoes;delete adidasProducer;return 0;
} 输出结果 3.抽象工厂模式
鞋厂为了扩大了业务不仅只生产鞋子把运动品牌的衣服也一起生产了。 Clothe和Shoes分别为衣服和鞋子的抽象产品类。
NiKeClothe和NiKeShoes分别是耐克衣服和耐克衣服的具体产品类。
// 基类 衣服
class Clothe
{
public:virtual void Show() 0;virtual ~Clothe() {}
};// 耐克衣服
class NiKeClothe : public Clothe
{
public:void Show(){std::cout 我是耐克衣服时尚我最在行 std::endl;}
};// 基类 鞋子
class Shoes
{
public:virtual void Show() 0;virtual ~Shoes() {}
};// 耐克鞋子
class NiKeShoes : public Shoes
{
public:void Show(){std::cout 我是耐克球鞋让你酷起来 std::endl;}
}; Factory为抽象工厂提供了创建鞋子CreateShoes()和衣服产品CreateClothe()对象的接口。
NiKeProducer为具体工厂实现了创建耐克鞋子和耐克衣服的方式。
// 总厂
class Factory
{
public:virtual Shoes *CreateShoes() 0;virtual Clothe *CreateClothe() 0;virtual ~Factory() {}
};// 耐克生产者/生产链
class NiKeProducer : public Factory
{
public:Shoes *CreateShoes(){return new NiKeShoes();}Clothe *CreateClothe(){return new NiKeClothe();}
};
main函数构造耐克工厂对象通过耐克工厂对象再创建耐克产品族的衣服和鞋子对象。同样对象不再使用时需要手动释放资源。
int main()
{// 生产耐克流程 //// 鞋厂开设耐克生产线Factory *niKeProducer new NiKeProducer();// 耐克生产线产出球鞋Shoes *nikeShoes niKeProducer-CreateShoes();// 耐克生产线产出衣服Clothe *nikeClothe niKeProducer-CreateClothe();// 耐克球鞋广告喊起nikeShoes-Show();// 耐克衣服广告喊起nikeClothe-Show();// 释放资源delete nikeShoes;delete nikeClothe;delete niKeProducer;return 0;
} 输出结果 三、适配器模式
适配器模式的作用是解决两个软件实体间的接口不兼容的问题。将一个接口转换成客户希望的另一个接口使接口不兼容的那些类可以一起工作。
适配器模式有两种实现方法类适配器和对象适配器。类适配器以多继承方式实现。对象适配器以组合的方式实现即适配器类中包含了适配者类对象。调用了适配者类中的方法即新的方法
一共包含三个类目标类、适配者类、适配器类。目标类中的接口和适配者类中的接口不兼容可通过引入适配器类在适配器类中保留了原目标类的接口名调用了适配者类接口中的功能对功能重新进行了封装然后通过目标类指针指向适配器类对象或者目标类引用引用适配器类对象就可调用新的功能完成对该接口的功能完善。
应用场景通过适配器完成USB与TypeC的对接。原先接口功能是USB接口新的接口是TypeC接口需要完成适配即可以把USB接口当成TypeC接口来使用。相当于给中间连了转换器
类适配器代码
/* Connect Usb port */
class CUsbDisk
{
public:virtual ~CUsbDisk() {}virtual void ConnectDevice(){cout Connect usb port. endl;}
};/* Connect Type-C port */
class CTypeCInterface
{
public:virtual ~CTypeCInterface() {}void ConnectDevice(){cout Connect Type-C port. endl;}
};/* Not only connect Usb port, but also connect Type-C port */
class CAdapter : public CUsbDisk, public CTypeCInterface
{
public:void ConnectDevice(){//调用了适配者类中的方法即完善了功能用旧的名字调用了新的功能。CTypeCInterface::ConnectDevice();}
};int main(int argc, char *argv[])
{//通过目标类指针指向适配器类对象调用了新的方法原先的接口及新的功能CUsbDisk *theDisk new CAdapter();theDisk-ConnectDevice();delete theDisk;return 0;
}
输出结果 对象适配器模式
/* Connect Usb port */
class CUsbDisk
{
public:virtual ~CUsbDisk() {}virtual void ConnectDevice(){cout Connect usb port. endl;}
};/* Connect Type-C port */
class CTypeCInterface
{
public:virtual ~CTypeCInterface() {}void ConnectDevice(){cout Connect Type-C port. endl;}
};/* Usb device connect phone */
class CAdapter : public CUsbDisk
{
public:CAdapter(){mpAdaptee new CTypeCInterface();}~CAdapter(){if (NULL ! mpAdaptee) {delete mpAdaptee;}}void ConnectDevice(){if (NULL ! mpAdaptee) {mpAdaptee-ConnectDevice();} else {cout Adapter abnormal. Connect fail! endl;}}private://包含了适配者类对象通过该对象调用了新的方法重新封装了旧接口。CTypeCInterface *mpAdaptee;
};int main(int argc, char *argv[])
{CUsbDisk *theDisk new CAdapter();theDisk-ConnectDevice();delete theDisk;return 0;
}
输出结果 或
/*** The Target defines the domain-specific interface used by the client code.*/
class Target {public:virtual ~Target() default;virtual std::string Request() const {return Target: The default targets behavior.;}
};/*** The Adaptee contains some useful behavior, but its interface is incompatible* with the existing client code. The Adaptee needs some adaptation before the* client code can use it.*/
class Adaptee {public:std::string SpecificRequest() const {return .eetpadA eht fo roivaheb laicepS;}
};/*** The Adapter makes the Adaptees interface compatible with the Targets* interface using multiple inheritance.*/
class Adapter : public Target, public Adaptee {public:Adapter() {}std::string Request() const override {std::string to_reverse SpecificRequest();std::reverse(to_reverse.begin(), to_reverse.end());return Adapter: (TRANSLATED) to_reverse;}
};/*** The client code supports all classes that follow the Target interface.*/
void ClientCode(const Target *target) {std::cout target-Request();
}int main() {std::cout Client: I can work just fine with the Target objects:\n;Target *target new Target;ClientCode(target);std::cout \n\n;Adaptee *adaptee new Adaptee;std::cout Client: The Adaptee class has a weird interface. See, I dont understand it:\n;std::cout Adaptee: adaptee-SpecificRequest();std::cout \n\n;std::cout Client: But I can work with it via the Adapter:\n;Adapter *adapter new Adapter;ClientCode(adapter);std::cout \n;delete target;delete adaptee;delete adapter;return 0;
} 结果如下
Client: I can work just fine with the Target objects:
Target: The default targets behavior.Client: The Adaptee class has a weird interface. See, I dont understand it:
Adaptee: .eetpadA eht fo roivaheb laicepSClient: But I can work with it via the Adapter:
Adapter: (TRANSLATED) Special behavior of the Adaptee.s
四、装饰器模式
装饰器模式是比较常用的一种设计模式Python中就内置了对于装饰器的支持。
具体来说装饰器模式是用来给对象增加某些特性或者对被装饰对象进行某些修改。 如上图所示需要被装饰的对象在最上方它自身可以有自己的实例一般通过抽象类来实现(Java中也可以通过接口实现)。
右侧中间是一个装饰器类或者接口其实内容与原对象基本一致不过我们自定义的装饰器一般会继承这个装饰器基类。
最下层就是具体的装饰器了可以看到具体装饰器类中需要包含被装饰对象成员也就是说装饰器需要和被装饰对象有同样的子类然后增加一些额外的操作。
下面的代码是一个买煎饼的例子如我们生活中所见可以选基础煎饼鸡蛋煎饼肉煎饼等然后再额外加别的东西。 代码如下
#includeiostream
#includestring
using namespace std;class Pancake//基类
{
public:string description Basic Pancake;virtual string getDescription(){ return description; }virtual double cost() 0;
};class CondimentDecorator :public Pancake//装饰器基类
{
public:string getDescrition();
};class MeatPancake :public Pancake//肉煎饼
{
public:MeatPancake(){ description MeatPancake; }double cost(){ return 6; }
};
class EggPancake :public Pancake//鸡蛋煎饼
{
public:EggPancake(){ description EggPancake; }double cost(){ return 5; }
};class Egg :public CondimentDecorator//额外加鸡蛋
{
public:Pancake* base;string getDescription(){ return base-getDescription() , Egg; }Egg(Pancake* d){ base d; }double cost(){ return base-cost() 1.5; }
};
class Potato :public CondimentDecorator//额外加土豆
{
public:Pancake* base;string getDescription(){ return base-getDescription() , Potato; }Potato(Pancake* d){ base d; }double cost(){ return base-cost() 1; }
};
class Bacon :public CondimentDecorator//额外加培根
{
public:Pancake* base;string getDescription(){ return base-getDescription() , Bacon; }Bacon(Pancake* d){ base d; }double cost(){ return base-cost() 2; }
};int main()
{Pancake* pan new EggPancake();pan Potato(pan);pan Bacon(pan);cout pan-getDescription() $ : pan-cost() endl;system(pause);return 0;
}