创建型模式
单例模式
在一个项目中,全局范围内,某一个类的实例有且仅有一个,通过这个唯一的实例向其他模块提供数据的全局访问。单例模式最典型的应用是任务队列.
template<class T>
class TaskQueue {
public:
static TaskQueue* getInstance() { // 向类外提供一个访问类内部唯一对象的接口
return instance;
}
void push(T task) {
taskQueue.push(task);
}
T front() {
return taskQueue.front();
}
void pop() {
taskQueue.pop();
}
private:
TaskQueue() = default; // 不能在类外创建对象,设置私有
TaskQueue(const TaskQueue&) = delete;
TaskQueue& operator=(const TaskQueue&) = delete;
static TaskQueue<T> *instance; // 类内部创建一个对象
std::queue<T> taskQueue;
};
template<class T>
TaskQueue<T>* TaskQueue<T>::instance = new TaskQueue;
- 饿汉式 如上代码,单例类定义出来后,实例对象就随着创建了。
内存开销大,线程安全
。 - 懒汉式 在第一次需要使用单例对象的时候才创建,初始化时
instance
置为nullptr
,使用时判断。内存开销小,线程不安全
。多线程需要加锁或者使用call_once
以及静态局部变量(指针改为变量)。
if (instance == nullptr) {
instance = new TaskQueue<T>;
}
- 在多线程情况下,使用懒汉式一般用静态局部变量的方式。因为
C++11
标准中,静态变量只有在第一次使用时才会被初始化。多个线程在使用前只有等待初始化完成才可以访问。这样只会初始化一次。
template<class T>
class TaskQueue {
public:
static TaskQueue& getInstance() {return instance;}
private:
TaskQueue() = default;
TaskQueue(const TaskQueue&) = delete;
TaskQueue& operator=(const TaskQueue&) = delete;
static TaskQueue instance;
};
template<class T>
TaskQueue<T> TaskQueue<T>::instance = TaskQueue();
工厂模式
工厂-用来生产某一类的对象。在程序中,如果需要频繁用到某一类的对象,由工厂创建,那就不需要自己创建和关心构造这个对象的细节,都被工厂封装好了。工厂模式并不是只能生产某一类对象,而是多种,由同一父类(抽象类)派生出来的子类的对象。相当于有一个工厂,他的产品是笔。他既可以生产铅笔又可以生产粉笔等等。。。
简单工厂模式
- 步骤
- 创建一个新的类, 可以将这个类称之为工厂类。对于简单工厂模式来说,需要的工厂类只有一个
- 在这个工厂类中添加一个公共的成员函数,通过这个函数来创建我们需要的对象,关于这个函数一般将其称之为工厂函数
- 关于使用,首先创建一个工厂类对象,然后通过这个对象调用工厂函数,这样就可以生产出一个指定类型的实例对象了
class Base {
public:
virtual void print() = 0;
virtual ~Base() {}
};
class A : public Base {
public:
void print() override {std::cout << "I am A\n";}
};
class B : public Base {
public:
void print() override {std::cout << "I am B\n";}
};
enum class Type : char{Son_A, son_B};
// 定义一个简单工厂类
class Factory {
public:
Base* Create(Type type) {
Base *ptr = nullptr;
switch (type) {
case Type::Son_A :
ptr = new A();
break;
case Type::son_B :
ptr = new B();
break;
default:
break;
}
return ptr;
}
};
int main() {
Factory *factory = new Factory();
Base *obj = factory->Create(Type::Son_A);
obj->print();
return 0;
}
工厂模式
每个工厂只生产一类对象,不再可以生产某个类的多个派生类对象。即工厂类的某一个派生类只生产产品类的某一个派生类。相当于现在老板有钱了,又多开了几个厂子,每个厂子分别生成各类型的笔。好处是当要新增某一个派生类产品时,不需要修改工厂的生产函数,破坏类的封装性。只需新增一个工厂类的派生类。
class Base {
public:
virtual void print() = 0;
virtual ~Base() {}
};
class A : public Base {
public:
void print() override {std::cout << "I am A\n";}
};
class B : public Base {
public:
void print() override {std::cout << "I am B\n";}
};
// 定义一个工厂类的父类
class Factory {
public:
virtual Base* create() = 0;
virtual ~Factory() {}
};
class A_Factory : public Factory {
public:
Base *create() override {return new A;}
};
class B_Factory : public Factory {
public:
Base *create() override {return new B;}
};
int main() {
Factory *factory = new A_Factory;
Base *obj = factory->create();
obj->print();
return 0;
}
抽象工厂模式
每个工厂生产的是一个某一类抽象的产品。意思是产品的属性需要指定。当然,每个属性也是一个类对象。
- 举例:建造一艘船,船有基础,中级,高级三种类型。分别对应三个工厂。
- 每种级别的船的配置(属性)不一样。在不同工厂建造船时需要传递不同的配置(配置类的对象)
总结
- 工厂模式创建的对象对应的类不需要提供抽象类【这产品类组件中没有可变因素】
- 抽象工厂模式创建的对象对应的类有抽象的基类【这个产品类组件中有可变因素】
- 工厂模式适用于产品的组件简单。抽象工厂适用于产品由多个组件组装,复杂的场景。
生成器模式
抽象工厂模式更加专注于生产一系列相关的对象,这些对象继承于同意父类,兄弟关系。但是生产对象的流程过于复杂,抽象工厂就难以满足需求了。
生成器模式也是生产一个对象,更专注于生产对象时的步骤。
- 生产一个产品类的对象的流程非常多,生成器模式下这些流程并不在产品类中完成,是在生成器中完成。而工厂模式不在意流程,流程都在产品类中完成。
原型模式
用一个已经存在的对象克隆出另一个对象,克隆出的对象和当前的对象可以是父子关系。
- 实现:父类定义虚函数
clone()
由子类重写,当父类指针指向子类对象,调用clone()
时,由于clone()
是虚函数,所以调用的是子象的clone()
,在函数内部调用拷贝构造,复制自己。
class Base {
public:
virtual Base* clone() = 0;
virtual void who() = 0;
virtual ~Base() {}
};
class A : public Base {
public:
Base* clone() override { return new A(*this);}
void who() override { std::cout << "I am A\n";}
};
int main() {
Base *obj = new A();
Base *a = obj->clone();
a->who();
}
结构型模式
适配器模式
两种不同的类之间相互交流,但他们的数据结构不相同,所以需要先转换数据。
转换的接口就是适配器模式。
提供转换接口的类就是适配器类。
代码过长
桥接模式
桥接模式的核心思想是将一个类的抽象部分与其实现部分分离。通过桥接对象,这两个部分可以独立地变化和扩展,而不必相互影响。桥接模式通过使用组合(而非继承)来实现这一目标,从而降低了类之间的耦合度。当他们需要组合在一起工作时,通过桥接模式连接成聚合关系。
享元模式
享元模式就是摒弃了在每个对象中都保存所有的数据的这种方式,通过数据共享(缓存)让有限的内存可以加载更多的对象。
- 将整个类拆分成保存静态数据和动态数据的两个类。所有动态类对象共享一个静态类对象.
- 当实例化一个完整数据时,将一个静态类对象和一个动态类对象聚合成一个对象。
行为模式
观察者模式
观察者模式允许我们定义一种订阅机制,可在对象事件发生时通知所有的观察者对象,使它们能够自动更新。观察者模式还有另外一个名字叫做“发布-订阅”模式。