定义:

单来源调用指一个类的生成工作只能由特定类来执行。

eg李宁牌鞋子只能由李宁专卖店生产

这个问题归结起来,也就是说在工厂模式中,指定的产品类只能通过具体的特定工厂类来生成,而不能自己new出来或者通过其他类生成。

具体的,我们就在代码实现中进行说明了。

这里我们来一步一步分析。

首先,一个类实例(对象)不能自己产生,那么。我们就需要屏蔽构造函数了。

那么,屏蔽了构造函数之后,如何获取一个实例呢。

有两种方案可以实现。

方案一:

通过继承获取构造函数执行权限。如代码

class base
{
protected:
base()
{
Trace("");
}
};
class driver:protected base
{
public:
void test()
{
base b;
}
}; int main(int argc, char const *argv[])
{
driver d;
d.test();
return ;
}

这个方案只是可以让一个类能够产生实例。单他和我们的意图严重偏离:

a实例和子类的生命周期一致。

b没有自主权。

c其他类也可以模拟他的实现,继承父类获取生成权,这显然是个垃圾方案。

方案二:类似单例模式方法处理

产品类 构造函数屏蔽,但是提供一个获取实例的共有方法

静态方法获取实例
class base
{
protected:
base()
{
Trace("");
}
public:
static base* getInstance();
}; base* base::getInstance()
{
return new base();
}
int main(int argc, char const *argv[])
{
// base* p = new base();
base * p = base::getInstance();
return ;
}

通过方案二,我们实现了一个类不能自己执行 base *p = new base()

类型绑定

那么下面我们的目标就是将这个产品类和具体可生产者进行绑定了。

如何绑定呢,对于一个特定的类,处理之,我们就想到了this指针

所以我们要做的就是,产品类构造函数依赖工厂类的this 指针

// 通过静态方法获取,且依赖driver的this指针。
// 但是此时也可以通过临时对象driver生成
class driver;
class base
{
protected:
base()//driver*)
{
Trace("");
}
public:
static base* getInstance(driver*);
}; base* base::getInstance(driver*)
{
return new base();
} class driver
{
public:
base* getInstance()
{
return base::getInstance(this);
}
};
int main(int argc, char const *argv[])
{ base * p = (driver()).getInstance(); //我们所期望的运行方式。
p = base::getInstance(new driver()); //产品类抓住漏洞强行生成自我
return ;
}

到这里,貌似我们的目标已经达到了,但是呢。如例子中的  p = base::getInstance(new driver());这个方法,本质还是base类自主生成的。

并不能符合我们的要求。

那么到这里,我们应该如何处理呢。

我能想到的就是,不光让base建立依赖driver的this指针,同时设置权限。才能执行getinstace()

首先给出最终代码了

// 抽象接口类,提供子类行为,同时定义权限值以及权限判断给base中的getinstace方法使用
class abstractDriver
{
protected:
bool _canCreate;
abstractDriver(bool can)
:_canCreate(can)
{}
public:
virtual bool canCreate(){
return _canCreate;
}
}; class base
{
protected:
base()
{
Trace("");
}
public:
static base* getInstance(abstractDriver*);
}; // 根据依赖的this对应类是否有权限执行决定生成
base* base::getInstance(abstractDriver*dr)
{
if (dr->canCreate())
/* code */
return new base();
else
return NULL;
} class driver:public abstractDriver
{
public:
driver()
:abstractDriver(false)
{
Trace("");
}
//在获取base实例前后修改权限。保证外部权限始终伪假
base* getInstance()
{
_canCreate = true;
base* p =base::getInstance(this);
_canCreate = false;
return p;
}
}; int main(int argc, char const *argv[])
{
base* p = base::getInstance(new driver());
cout << p <<endl; //NULL,未生成实例
p = (driver()).getInstance();
cout << p <<endl;
p = (driver()).getInstance();
cout << p <<endl;
return ;
}

好了,最终的实现版本就完成了。

符合我们的目标

base类只能通过driver类生成。

最后,我们可以发现,这个实现中的getInstace方法让我们想到了单例模式的实现。

不同的是单例模式的结果是最终

a只有一个类型实例产生,

b生成方式可以是自主的 base::getinstance()

而我们的单来源调用,

a。生成实例个数不一定是一个,只是生成方式限定了

b。不能通过直接调用base::getinstance()生成。

之所以拿出来将两个模式进行比较,是因为:单来源调用并不是23种设计模式中的一种,初次看他时,我自己也是一脸蒙蔽。其次,两者都是很重要,很常用的方法。

个人源码实现github地址:https://github.com/langya0/design_pattern_study/tree/master/singleCall

23种设计模式C++实现及扩展代码:https://github.com/langya0/design_pattern_study

参考《Single Call 模式

singleCall单来源调用解析及实现的更多相关文章

  1. Form表单 JSON Content-type解析

    Form表单 JSON Content-type解析 1 表单Form概述 在Form表单中,参数一般有: action 表单提交的url method 提交方式:post get name 表单的属 ...

  2. HTML5新表单新功能解析

    HTML5新增了很多属性功能.但是有兼容性问题,因为这些表单功能新增的.我这里做了一个简单的练习,方便参考.如果完全兼容的话,那我们写表单的时候就省了很多代码以及各种判断. <!DOCTYPE ...

  3. 深入理解java虚拟机(十一) 方法调用-解析调用与分派调用

    方法调用过程是指确定被调用方法的版本(即调用哪一个方法),并不包括方法执行过程.我们知道,Class 文件的编译过程中并不包括传统编译中的连接步骤,一切方法调用在 Class 文件调用里面存储的都只是 ...

  4. PHPCMS V9表单向导调用及分页

    参考资料如下:v9_form_tlj为你的表单数据表,`flqh`,`title`,`sj`,`username`,`datetime` 为你表单内的字段,page="$_GET" ...

  5. html文件form表单action调用servlet连接mysql数据库实例

    web.xml文件 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi=&qu ...

  6. ajax使用formdata 提交excel文件表单到rails解析

    .modal-body .container-fluid .row .col-md-12 1.下载模板文件 = link_to '模板文件' .row .col-md-12 = form_tag '' ...

  7. js 对有“命名空间”的表单做深度解析

    问题描写叙述:一个大表单中,可能包括几十个字段.这些字段在数据库中的映射非常可能不在一张表中,为了降低后台操作的工作量,我们应该在前台提交的时候对数据做初步处理. 举例说明: watermark/2/ ...

  8. java生成快递单并调用打印机打印

    生成快递单过程中需要生成条形码,生成条形码可参考:https://www.cnblogs.com/linbky/p/12091248.html 下面这段代码生成的快递单是完全符合京东快递的10 x 1 ...

  9. Dwz/Jquery--使用Ajax提交表单时调用表单设置的校验

    案例 今天有一个需求就是点击按钮时,使用ajax方式提交表单,而且不是直接用form表单下的submit按钮提交,表单中用的校验是dwz 自带的校验方式,表单模板如下: <li><d ...

随机推荐

  1. 基于Rest服务实现的RPC

    前言:现在RPC成熟的框架已经很多了,比喻Motan和Dubbo,但是今天我这里提供一种基于Rest服务的Rpc.和上一篇连着的http://www.cnblogs.com/LipeiNet/p/58 ...

  2. JSON学习之二

    1.JSON语法是JavaScript对象表示法的子集,语法规则: **数据在名称/值对中 **数据由逗号分隔 **花括号保存对象 **方括号保存数组 2.JSON名称/值对:JSON数据的书写格式是 ...

  3. 抛弃强大的TFS ,借助于BugTracker.NET + Visual Source Safe + SourceLink搭建项目开发环境

    微软公司的Team Foundation Server是个强大的项目管理工具,如果用.NET开发,它应该是首选的项目管理平台.TFS的成本比较高,而且和Visual Studio集成紧密.比如TSF有 ...

  4. Android入门(五)UI-单位与尺寸、ListView

    原文链接:http://www.orlion.ga/453/ 一.单位与尺寸 布局文件中一共有以下单位供选择:px,pt,dp,sp px:是像素,屏幕中可见的最小元素单位. pt:是磅,1磅等于1/ ...

  5. MongoDB的学习--索引类型和属性

    索引类型 MongDB的索引分为以下几种类型:单键索引.复合索引.多键索引.地理空间索引.全文本索引和哈希索引 单键索引(Single Field Indexes) 在一个键上创建的索引就是单键索引, ...

  6. 理解ip和端口

    理解IP和端口 IP地址是一个规定,现在使用的是IPv4,既由4个0-255之间的数字组成,在计算机内部存储时只需要4个字节即可.在计算机中,IP地址是分配给网卡的,每个网卡有一个唯一的IP地址,如果 ...

  7. JavaScript中{}+{}

    在 JavaScript 中,加法的规则其实很简单,只有两种情况: 把数字和数字相加 把字符串和字符串相加 所有其他类型的值都会被自动转换成这两种类型的值. 为了能够弄明白这种隐式转换是如何进行的,我 ...

  8. JS兼容所有浏览器的一段加入收藏代码,设置为首页

    <script language="javascript" type="text/javascript"> function addfavorite ...

  9. Visual Studio 2010 起始页中 不显示最近使用的项目问题,解决办法

    最近新装了vs2010,发现打开vs2010 后 起始页面中的最近使用的栏目中 并未显示最近加载的项目 解决办法如下: 运行 regedit 打开下面的键值: HKEY_CURRENT_USER/So ...

  10. webpack打包压缩工具的使用方法

    具体使用方法参考来源http://www.cnblogs.com/Leo_wl/p/4793722.html 必须注意的地方: 一.webpack在nodejs环境下运行 二,每个目录下都必须有一个w ...