设计模式 之singleton,Builer,Prototype

Singleton

问题:

创建一个唯一的对象

方案:

在这里插入图片描述

Code:

经典方案

//single.h
#ifndef SINGLE_H_
#define SINGLE_H_

#include<iostream>
#include<memory>
#include<mutex>
using namespace std;

class Single{
public:
	static std::shared_ptr<Single> Instance();
	~Single();
protected:
	//Construction function is private
	Single();
private:
	//shared_ptr for RAII
	static std::shared_ptr<Single> instance;
	static std::mutex mx;
};
#endif /* SINGLE_H_ */
//single.cpp
#include "single.h"
using namespace std;

std::shared_ptr<Single> Single::instance = nullptr;
std::mutex Single::mx;
std::shared_ptr<Single> Single::Instance()
{
	//double check for multiThread
	if(instance == nullptr){
		std::lock_guard<std::mutex> lk(mx);
		if(instance == nullptr){
			instance = std::shared_ptr<Single>(new Single());
		}
	}
	return instance;
}

Single::Single(){
	cout << "enter into Single Construction" << endl;
}

Single::~Single(){
	cout << "enter into Single Destruction" << endl;
}
//main.cpp
#include "single.h"
using namespace std;

int main() {

	std::shared_ptr<Single> si = Single::Instance();
	std::shared_ptr<Single> s2 = Single::Instance();
	cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
	return 0;
}

运行结果:

enter into Single Construction
!!!Hello World!!!
enter into Single Destruction

shared_ptr和mutex都是C++11的标准,以上这种方法的优点是:
基于 shared_ptr, 用了C++比较倡导的 RAII思想,用对象管理资源,当 shared_ptr 析构的时候,new 出来的对象也会被 delete掉。以此避免内存泄漏。
加了锁,使用互斥量来达到线程安全。这里使用了两个 if判断语句的技术称为双检锁;好处是,只有判断指针为空的时候才加锁,避免每次调用 get_instance的方法都加锁,锁的开销毕竟还是有点大的。

可以使用局部静态变量来实现单列模式:(推荐使用)

#include <iostream>

class Singleton
{
public:
    ~Singleton(){
        std::cout<<"destructor called!"<<std::endl;
    }
    Singleton(const Singleton&)=delete;
    Singleton& operator=(const Singleton&)=delete;
    static Singleton& get_instance(){
        static Singleton instance;
        return instance;

    }
private:
    Singleton(){
        std::cout<<"constructor called!"<<std::endl;
    }
};

int main(int argc, char *argv[])
{
    Singleton& instance_1 = Singleton::get_instance();
    Singleton& instance_2 = Singleton::get_instance();
    return 0;
}

这种方法又叫做 Meyers’ SingletonMeyer’s的单例, 是著名的写出《Effective C++》系列书籍的作者 Meyers 提出的。所用到的特性是在C++11标准中的Magic Static特性:
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
如果当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束。

这样保证了并发线程在获取静态局部变量的时候一定是初始化过的,所以具有线程安全性。
C++静态变量的生存期 是从声明到程序结束,这也是一种懒汉式。
这是最推荐的一种单例实现方式:

  1. 通过局部静态变量的特性保证了线程安全 (C++11, GCC > 4.3, VS2015支持该特性);
  2. 不需要使用共享指针,代码简洁;
  3. 注意在使用的时候需要声明单例的引用 Single& 才能获取对象。

C++ 单例模式总结与剖析
Singleton 模式 VS 全局变量: 很多情况下,我们使用 Singleton 模式达到的效果和全局变量达到的效果类似。但是,全局变量不能防止实例化多个对象。GoF 在《设计模式》中给出了 Singleton 模式的意图“保证一个类仅有一个对象,并提供一个访问它的全局访问点”,因此全局变量可以达到后面半句的效果,但是却不能保证仅有一个对象被实例化。另外,使用全局变量将使得对象在无论是否用到都要被创建,而 Singleton 模式则没有这个瑕疵。

Builder Pattern

问题:

分块去建造复杂的大型对象;
在这里插入图片描述

Code:

Product 表示需要构建的目标对象类

//Product.h
#ifndef _PRODUCT_H_
#define _PRODUCT_H_
class Product
{
public:
	Product();
	~Product();
	void ProducePart();
protected:
private:
};
//需要构建的目标对象的局部类
class ProductPart
{
public:
	ProductPart();
	~ProductPart();
	ProductPart* BuildPart();
protected:
private:
};
#endif //~_PRODUCT_H_
//Product.cpp
#include "Product.h"
#include <iostream>
using namespace std;
Product::Product()
{
	ProducePart();
	cout<<"return a product"<<endl;
}
Product::~Product()
{
}
void Product::ProducePart()
{
	cout<<"build part of product.."<<endl;
}
ProductPart::ProductPart()
{
	//cout<<"build productpart.."<<endl;
}
ProductPart::~ProductPart()
{
}
ProductPart* ProductPart::BuildPart()
{
	return new ProductPart;
}

Builder 目标对象构造器,用于提供分步构造对象的方法

//Builder.h
#ifndef _BUILDER_H_
#define _BUILDER_H_
#include <string>
using namespace std;
class Product;
class Builder
{
public:
virtual ~Builder();
virtual void BuildPartA(const string& buildPara) = 0;
virtual void BuildPartB(const string& buildPara) = 0;
virtual void BuildPartC(const string& buildPara) = 0;
virtual Product* GetProduct() = 0;
protected:
Builder();
private:
};
class ConcreteBuilder:public Builder
{
public:
ConcreteBuilder();
~ConcreteBuilder();
void BuildPartA(const string& buildPara);
void BuildPartB(const string& buildPara);
void BuildPartC(const string& buildPara);
Product* GetProduct();
protected:
private:
};
#endif //~_BUILDER_H_
//Builder.cpp
#include "Builder.h"
#include "Product.h"
#include <iostream>
using namespace std;
Builder::Builder()
{
}
Builder::~Builder()
{
}
ConcreteBuilder::ConcreteBuilder()
{
}
ConcreteBuilder::~ConcreteBuilder()
{
}
void ConcreteBuilder::BuildPartA(const string& buildPara)
{
	cout<<"Step1:Build PartA..."<<buildPara<<endl;
}
void ConcreteBuilder::BuildPartB(const string& buildPara)
{
	cout<<"Step1:Build PartB..."<<buildPara<<endl;
}
void ConcreteBuilder::BuildPartC(const string& buildPara)
{
	cout<<"Step1:Build PartC..."<<buildPara<<endl;
}
Product* ConcreteBuilder::GetProduct()
{
	BuildPartA("pre-defined");
	BuildPartB("pre-defined");
	BuildPartC("pre-defined");
	return new Product();
}

Director 指挥者类,用于决定调用的顺序,返回完整的目标对象;
有些情况下可以直接由Builder构造器直接构造出完整的目标对象;

//Director.h
#ifndef _DIRECTOR_H_
#define _DIRECTOR_H_
class Builder;
class Director
{
public:
Director(Builder* bld);
~Director();
void Construct();
protected:
private:
Builder* _bld;
};
#endif //~_DIRECTOR_H_
//Director.cpp
#include "director.h"
#include "Builder.h"
Director::Director(Builder* bld)
{
	_bld = bld;
}
Director::~Director()
{
}
void Director::Construct()
{
	_bld->BuildPartA("user-defined");
	_bld->BuildPartB("user-defined");
	_bld->BuildPartC("user-defined");
}
//main.cpp
#include "Builder.h"
#include "Product.h"
#include "Director.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
	Director* d = new Director(new ConcreteBuilder());
	d->Construct();
	return 0;
}

Prototype pattern

问题:

自我复制,通过已有对象去构建新的对象;
在这里插入图片描述

Code:
//Prototype.h
#ifndef _PROTOTYPE_H_
#define _PROTOTYPE_H_
class Prototype
{
public:
virtual ~Prototype();
virtual Prototype* Clone() const = 0;
protected:
Prototype();
private:
};
class ConcretePrototype:public Prototype
{
public:
ConcretePrototype();
ConcretePrototype(const ConcretePrototype& cp);
~ConcretePrototype();
Prototype* Clone() const;
protected:
private:
};
#endif //~_PROTOTYPE_H_
//Prototype.cpp
#include "Prototype.h"
#include <iostream>
using namespace std;
Prototype::Prototype()
{
}
Prototype::~Prototype()
{
}
Prototype* Prototype::Clone() const
{
	return 0;
}
ConcretePrototype::ConcretePrototype()
{
}
ConcretePrototype::~ConcretePrototype()
{
}
//拷贝构造函数是实现的重点
//deep copy ?
ConcretePrototype::ConcretePrototype(const ConcretePrototype& cp)
{
	cout<<"ConcretePrototype copy ..."<<endl;
}
Prototype* ConcretePrototype::Clone() const
{
	return new ConcretePrototype(*this);
}
//main.cpp
#include "Prototype.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
	Prototype* p = new ConcretePrototype();
	Prototype* p1 = p->Clone();
	return 0;
}
总结:

Prototype 模式和 Builder 模式、AbstractFactory 模式都是通过一个类(对象实例)来专门负责对象的创建工作(工厂对象),它们之间的区别是:Builder 模式重在复杂对象的一步步创建(并不直接返回对象),AbstractFactory 模式重在产生多个相互依赖类的对象,而 Prototype 模式重在从自身复制自己创建新类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值