工厂模式
目的
- 程序更规范有条理
- 当我们创建实例对象时,如果不仅仅做赋值这样简单的事情,而是有一大段逻辑,那这个时候我们要将所有的初始化逻辑都写在构造函数中吗? 显然,这样使得代码很难看
- 降低耦合度,提高可阅读性
- 将长的代码进行”切割”,再将每一个小逻辑都”封装”起来,这样可以降低耦合度,修改的时候也可以直奔错误段落
实现方式
区别
- 懒汉式指系统运行中,实例并不存在,只有当需要使用该实例时,才会去创建并使用实例
- 饿汉式指系统一运行,就初始化创建实例,当需要时,直接调用即可
简单工厂方式
简单工厂模式是由一个工厂对象决定创建出来哪一种产品类的实例
特点
- 由一个工厂类根据传入的参数,动态决定应该创建哪一类产品类
缺点
- 每次新增一个类时,都需要改变工厂函数,破坏了封装性
- (如果生产厂家需要新增一个产品,那么工厂函数Factory就需要跟着改变,所以上面的工厂模式违背了开放封闭原则)
- 开放封闭原则:软件实体(类、模块、函数)可以扩展,但是不可修改
#include <iostream>
#include "stdafx.h"
using namespace std;
class Product{
public:
virtual void show = 0;
}
class Product_A : public Product{
public:
void show{
cout << "Product_A" << endl;
}
}
class Product_B : public Product{
public:
void show{
cout << "Product_B" << endl;
}
}
class Factory{
public:
Product* Create(int i){
switch(i){
case 1:
return new Product_A;
break;
case 2:
return new Product_A;
break;
default:
break;
}
}
}
工厂方法模式
多个工厂,多个产品,每个产品对应一个工厂 工厂和产品都是通过虚基类的方式构建
特点
- 定义用于创建对象的接口,让子类决定实例化哪个类
- 当增加一个新产品时,同时增加一个新工厂。
- 增加新工厂属于扩展,不会修改以前工厂类和产品类的任何代码
缺点
- 每增加一个新的产品,就需要增加一个新的工厂
#include <iostream>
#include "stdafx.h"
using namespace std;
class Product{
public:
virtual void show() =0;
};
class Product_A : public Product{
public:
void show(){
cout << "Product_A" << endl;
}
};
class Product_B : public Product{
public:
void show(){
cout << "Product_B" << endl;
}
};
class Factory{
public:
virtual Product* create() = 0;
};
class Factory_A{
public:
Product* create(){
return new Product_A;
}
};
class Factory_B{
public:
Product* create(){
return new Product_B;
}
};
抽象工厂模式
多个工厂,多个产品,并且每个产品可以包含多个型号 工厂和产品通过虚基类构建,每个工厂类可以生产同一个产品的多个型号
特点
- 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
优点
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象
- 易于交换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,这样就使得改变一个应用的具体工厂变得非常容易,只需要改变具体工厂即可使用不同的产品配置。
- 让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂实现分离,不会出现在客户代码中。
缺点
- 产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
#include <iostream>
using namespace std;
class product1{
public:
virtual void show() = 0;
};
class product1_a : public product1{
public:
void show(){
cout << "product1 a" <<endl;
}
};
class product1_b : public product1{
public:
void show(){
cout << "product1 b" <<endl;
}
};
class product2{
public:
virtual void show() = 0;
};
class product2_a : public product1{
public:
void show(){
cout << "product2 a" <<endl;
}
};
class product2_b : public product1{
public:
void show(){
cout << "product2 b" <<endl;
}
};
class Factory{
public:
virtual product1* create1() = 0;
virtual product2* create2() = 0;
};
class FactoryA{
public:
product1* create1(){
return new product1_a;
}
product2* create2(){
return new product1_b;
}
};
class FactoryB{
public:
product1* create1(){
return new product2_a;
}
product2* create2(){
return new product2_b;
}
};
单例模式
目的
- 全局只有一个实例
- 不能通过new来构建对象
- 构造函数必须私有
- 类内部必须new出对象 -> static方法
- 不能通过new来构建对象
要点
- 全局只有一个实例,使用static实现,构造设为私有
- 通过公共接口获得实例
- 线程安全
- 禁止拷贝和赋值
实现方式
区别
- 懒汉式指系统运行中,实例并不存在,只有当需要使用该实例时,才会去创建并使用实例
- 饿汉式指系统一运行,就初始化创建实例,当需要时,直接调用即可
懒汉式线程不安全
#include <iostream>
#include <mutex>
#incldue <pthread.h>
class SingleInstance{
public:
// 获取单例对象
static SingleInstance* GetInstance();
// 释放单例
static void deleteInstance();
// 打印
void Print();
private:
// 禁止构造和析构
SingleInstance();
~SingleInstance();
// 禁止拷贝和赋值
SingleInstance(const SingleInstance& single);
const SingleInstance& operator=(const SingleInstance& single);
// 对象
static SingleInstance* m_SingleInstance;
};
SingleInstance* SingleInstance::m_SingleInstance = NULL;
SingleInstance* SingleInstance::GetInstance(){
if(m_SingleInstance == NULL){
// 有线程竞争的问题,可能会创建多个实例
// 使用new构建,并没有用shared_ptr构建
m_SingleInstance = new (std::nothrow) SingleInstance;
}
return m_SingleInstance;
}
void SingleInstance::deleteInstance(){
if(m_SingleInstance){
delete m_SingleInstance;
m_SingleInstance = NULL;
}
}
void SingleInstance::Print(){
std::cout << this << std::endl;
}
SingleInstance::SingleInstance()
{
std::cout << "构造函数" << std::endl;
}
SingleInstance::~SingleInstance()
{
std::cout << "析构函数" << std::endl;
}
线程安全的懒汉式使用静态声明的方式
class Singleton
{
public:
~Singleton(){
std::cout<<"destructor called!"<<std::endl;
}
//或者放到private中
Singleton(const Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
static Singleton& get_instance(){
//关键点!
static Singleton instance;
return instance;
}
//不推荐,返回指针的方式
/*static Singleton* get_instance(){
static Singleton instance;
return &instance;
}*/
private:
Singleton(){
std::cout<<"constructor called!"<<std::endl;
}
};
线程安全懒汉式使用锁的方式
#include <iostream>
#include <memory>
#include <mutex>
class Singleton{
public:
typedef std::shared_ptr<Singleton> Ptr;
~Singleton(){
std::cout<< "destructor called" <<std::endl;
}
Singleton(Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Ptr Singleton(){
// 先判断是否符合加锁条件
if(m_singleton == nullptr){
std::lock_guard<std::mutex> lk(m_mutex);
// 保证单例
if(m_singleton == nullptr){
m_singleton = std::shared_ptr<Singleton> (new Singleton);
}
}
return m_singleton;
}
private:
static Singleton m_singleton;
static std::mutex m_mutex;
};
Singleton::Ptr Singleton::m_singleton = nullptr;
std::mutex Singleton::m_mutex;
饿汉式
class Singleton{
public:
static Singleton* getSingleton();
static void deletesingle();
private:
Singleton();
~Singleton();
Singleton(const Singleton& single);
const Singleton& operator=(const Singleton& single);
static Singleton* single;
};
Singleton* Singleton::single = new(std::nothrow) Singleton;
Singleton* Singleton::getSingleton(){
return single;
}
void Singleton::deletesingle(){
if(single){
delete single;
single = NULL;
}
}
Singleton::Singleton(){
}
Singleton::~Singleton(){
}
面试题
- 懒汉模式和恶汉模式的实现(判空!!!加锁!!!),并且要能说明原因(为什么判空两次?)
- 构造函数的设计(为什么私有?除了私有还可以怎么实现(进阶)?)
- 对外接口的设计(为什么这么设计?)
- 单例对象的设计(为什么是static?如何初始化?如何销毁?(进阶))
- 对于C++编码者,需尤其注意C++11以后的单例模式的实现(为什么这么简化?怎么保证的(进阶))
观察者模式
定义
- 被观察者叫做subject,观察者叫做observer
- 定义对象之间的一对多的依赖关系,当每个对象改变,所有依赖它的对象都会得到通知并更新
观察者中的角色
- subject
- 目标知道它的观察者。可以有任意多个观察者观察同一个目标
- 提供注册和删除观察者对象的接口
- Observer
- 为那些在目标发生改变时需获得通知的对象定义一个更新接口
- ConcreteSubject
- 将有关状态存入各ConcreteObserver对象
- 当它的状态发生改变时,向它的各个观察者发出通知
- ConcreteObserver
- 维护一个指向ConcreteSubject对象的引用
- 存储有关状态,这些状态应与目标的状态保持一致
- 实现Observer的更新接口以使自身状态与目标的状态保持一致
优点
- 实现表示层和数据逻辑层的分离
- 观察者支持广播通信,观察目标会向所有的注册的
目的
- 程序更规范有条理
- 当我们创建实例对象时,如果不仅仅做赋值这样简单的事情,而是有一大段逻辑,那这个时候我们要将所有的初始化逻辑都写在构造函数中吗? 显然,这样使得代码很难看
- 降低耦合度,提高可阅读性
- 将长的代码进行”切割”,再将每一个小逻辑都”封装”起来,这样可以降低耦合度,修改的时候也可以直奔错误段落
场景
- 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用
- 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。
实现方式
#include <iostream>
#include <list>
using namespace std;
class Observer{
public:
virtual void Update(int) =0;
};
class Subject{
public:
virtual void attach(c* ) =0;
virtual void detach(Observer* ) =0;
virtual void notify() =0;
};
class concreateobserver : public Observer{
public:
concreateobserver(Subject* subject){
m_subject = subject;
}
void Update(int value){
cout << "concreate observer get the update: " << value << endl;
}
private:
Subject* m_subject;
};
class concreatesubject : public Subject{
public:
void attach(Observer* pobserver);
void detach(Observer* pobserver);
void notify();
void setstate(int state){
m_state = state;
}
private:
std::list<Observer*> m_observerList;
int m_state;
};
void ConcreteSubject::Attach(Observer *pObserver)
{
m_ObserverList.push_back(pObserver);
}
void ConcreteSubject::Detach(Observer *pObserver)
{
m_ObserverList.remove(pObserver);
}
void ConcreteSubject::Notify()
{
std::list<Observer *>::iterator it = m_ObserverList.begin();
while (it != m_ObserverList.end())
{
(*it)->Update(m_iState);
++it;
}
}