文章目录
本章内容概述
本文意在记录笔者在学习设计模式相关内容时记录笔记之用,同时适时加入笔者自己的体会与理解,希望能够加深笔者的印象,对读者更好的理解常见的设计模式有所帮助。
一、常见设计模式
设计模式有很多种,在《大话设计模式》一书中,共提到了24种,并不是每一种都熟稔于心,但是必须熟悉常见的设计模式和其设计理念,并在实际设计中加以应用,才能做到举一反三,触类旁通。
1.设计模式原则
设计模式一般具备六大设计原则,分别是:
单一职责原则
:对于一个类,应当仅有一个使其发生改变的原因。
开放封闭原则
:面对新的需求,可以通过增添代码来实现,但不能改动已有的代码。
里氏代换原则
:基类一定适用于派生类,即在程序中,即便将所有基类替换成派生类,也不影响结果。
依赖倒转原则
:抽象不依赖细节,细节依赖抽象,即针对接口编程,而不是针对实现编程。
迪米特原则
:如果两个类不直接通信,则不应当发生直接的相互作用。如果一个类需要调用另一个类的某个方法,则可以通过第三个类转发此调用。
接口隔离原则
:每个接口中,不存在派生类用不到却必须实现的方法,否则应当将接口拆分,使用多个隔离的接口。
2.设计模式分类
设计模式一般分为三类,分别如下:
创造型模式
:单例模式、工厂模式、建造者模式、原型模式。
结构型模式
:适配器模式、桥接模式、外观模式、组合模式、装饰模式、享元模式、代理模式。
行为型模式
:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式。
3.常见设计模式
本文主要介绍几种常见的设计模式,分别如下:
单例模式
:保证一个类仅有一个实例,并提供访问他的一个全局访问点。
工厂模式
:包括简单工厂模式、抽象工厂模式、工厂方法模式:
简单工厂模式
:主要用于创建对象,通过一个工厂,实现根据不同的输入条件产生不同的类,并且根据类内重写虚函数的不同实现不同的调用结果。
工厂方法模式
:对简单工厂模式的修正,将选择判断交给客户端实现,这样的设计可以使得在添加新功能时无需修改现有的类,直接修改客户端即可。
抽象工厂模式
:定义一个创建一系列相关或相互依赖的借口,而无需指定具体的类。
观察者模式
:定义一种一对多的关系,使得多哥观察对象同时监听一个主题对象,在主题对象发生变化时,通知所有观察者更新自己。
装饰模式
:可以动态地给对象添加额外职责,相比于生成派生类更为灵活。
二、单例模式
单例模式
,保证能且仅能实例化出一个对象,并提供一个访问该类的全局访问点,通常应用于文件系统和打印程序。
不难理解,在一个操作系统中,有且仅有一个文件系统,因此仅有一个实例;而对于打印程序,虽然一台主机可以连接多台打印机,但是计算机长的打印程序有且仅有一个,从而避免两个打印作业同时输出到打印机。
对于单例模式,有多种实现模式,一般分为两种:懒汉模式(在第一次用到类的时候实例化),饿汉模式(类定义的时候就实例化),接下来分别进行分析。
1.线程不安全的懒汉模式
将类的构造函数、拷贝构造和赋值运算符重载全部设为私有函数,同时定义静态类型的成员函数,返回已经创建好的类对象的指针,此处必须是静态成员函数,不做详细解释。
class Singleton{
private:
static Singleton * instance;
Singleton(){}
Singleton(const Singleton& tmp){}
Singleton& operator=(const Singleton& tmp){}
public:
static Singleton* getInstance()
{
if(instance == NULL)
{
instance = new Singleton();
}
return instance;
}
};
Singleton* Singleton::instance = NULL;
但是需要注意的是,这样的实现方式在多线程环境下是不安全的,如果当多个线程同时创建该类对象,则有可能不满足单例模式要求,因此还需要探讨更合适的方式。
2.线程安全的懒汉模式
对于多线程不安全的情况,可以通过加锁的方式解决,即在判断是否已经创建对象时进入临界区,从而保证经由一个线程可以访问,但是也会导致其余线程全部被阻塞。对于多线程的分析,碍于笔者水平首先,点到即止。
3.饿汉模式
在类定义时,初始化一个类对象指针,并通过静态成员函数返回该值真,同时可以保证在多线程模式下的安全性,笔者更推荐使用该模式。
二、工厂模式
工厂模式一般分为三种:简单工厂模式,工厂方法模式和抽象工厂模式,分别进行分析。
1.简单工厂模式
在创建对象时,根据输入不同可以产生不同的类对象,并且通过虚函数可以执行不同的功能,得到不同的结果。适用于针对不同情况创建类时,只需传入参数而无需了解实现,实现代码如下:
class operation { public: int v1; int v2; virtual double calculate() = 0; };
class add_op :public operation { double calculate() { return v1 + v2; } };
class sub_op :public operation { double calculate() { return v1 - v2; } };
class mul_op :public operation { double calculate() { return v1 * v2; } };
class div_op :public operation { double calculate() { return v1 / v2; } };
class factory
{
public:
static operation* createProduct(char op)
{
if (op == '+') { return new add_op(); }
else if (op == '-') { return new sub_op(); }
else if (op == '*') { return new mul_op(); }
else if (op == '/') { return new div_op(); }
else { return nullptr; }
}
};
但是不难看出,这样的设计并不满足开放封闭原则,如果需要增加功能,仍需修改现有代码,接下来对其进行优化。
2.工厂方法模式
为了满足开放封闭原则,可以对工厂进行分类,每个工厂只产生特定的产品,无需进行判断,进而使得在添加新功能时,只增加新工厂即可,无需修改判断条件,代码如下:
class operation { public: int v1; int v2; virtual double calculate() = 0; };
class add_op :public operation { double calculate() { return v1 + v2; } };
class sub_op :public operation { double calculate() { return v1 - v2; } };
class mul_op :public operation { double calculate() { return v1 * v2; } };
class div_op :public operation { double calculate() { return v1 / v2; } };
class factory { public: virtual operation* createProduct() = 0; };
class add_f :public factory { operation* createProduct() { return new add_op; } };
class sub_f :public factory { operation* createProduct() { return new sub_op; } };
class mul_f :public factory { operation* createProduct() { return new mul_op; } };
class div_f :public factory { operation* createProduct() { return new div_op; } };
3.抽象工厂模式
针对具体问题设计出一系列功能类似的产品,并根据用户需求对外提供服务接口,此处不作详解。
三、观察者模式
观察者会根据被观察者的状态变化,更新自己的状态。
在观察者类中,应当包含被观察者对象,从而更新自身状态;在被观察者类中,应当包括全部观察此被观察者的观察者对象,以便发送通知使其更改自身状态,代码如下:
class teacher;
class student
{
protected:
string name;
teacher* t;
student(string _name, teacher* _t) :name(_name), t(_t) { }
public:
virtual void update() = 0;
};
class sleepy_student :public student
{
public:
sleepy_student(string _name, teacher* _t) :student(_name, _t){ }
void update() { cout << name << " wake up" << endl; }
};
class talking_student :public student
{
public:
talking_student(string _name, teacher* _t) :student(_name, _t) { }
void update() { cout << name << " shut up" << endl; }
};
class teacher
{
protected:
vector<student*> group;
public:
void attach(student* s) { group.push_back(s); }
void detach(student* s)
{
for (int i = 0; i < group.size(); i++)
{
if (group[i] == s)
{
group.erase(group.begin() + i);
return;
}
}
}
void notify()
{
for (int i = 0; i < group.size(); i++)
{
group[i]->update();
}
}
};
本章总结
本章主要介绍了集中常见的设计模式,更多的设计模式的知识笔者会酌情继续补充,那么本章就到此结束,希望对读者初步了解设计模式有所帮助。
最后,我是Alkaid#3529,一个追求不断进步的学生,期待你的关注!