singleCall单来源调用解析及实现
定义:
单来源调用指一个类的生成工作只能由特定类来执行。
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单来源调用解析及实现的更多相关文章
- Form表单 JSON Content-type解析
Form表单 JSON Content-type解析 1 表单Form概述 在Form表单中,参数一般有: action 表单提交的url method 提交方式:post get name 表单的属 ...
- HTML5新表单新功能解析
HTML5新增了很多属性功能.但是有兼容性问题,因为这些表单功能新增的.我这里做了一个简单的练习,方便参考.如果完全兼容的话,那我们写表单的时候就省了很多代码以及各种判断. <!DOCTYPE ...
- 深入理解java虚拟机(十一) 方法调用-解析调用与分派调用
方法调用过程是指确定被调用方法的版本(即调用哪一个方法),并不包括方法执行过程.我们知道,Class 文件的编译过程中并不包括传统编译中的连接步骤,一切方法调用在 Class 文件调用里面存储的都只是 ...
- PHPCMS V9表单向导调用及分页
参考资料如下:v9_form_tlj为你的表单数据表,`flqh`,`title`,`sj`,`username`,`datetime` 为你表单内的字段,page="$_GET" ...
- html文件form表单action调用servlet连接mysql数据库实例
web.xml文件 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi=&qu ...
- ajax使用formdata 提交excel文件表单到rails解析
.modal-body .container-fluid .row .col-md-12 1.下载模板文件 = link_to '模板文件' .row .col-md-12 = form_tag '' ...
- js 对有“命名空间”的表单做深度解析
问题描写叙述:一个大表单中,可能包括几十个字段.这些字段在数据库中的映射非常可能不在一张表中,为了降低后台操作的工作量,我们应该在前台提交的时候对数据做初步处理. 举例说明: watermark/2/ ...
- java生成快递单并调用打印机打印
生成快递单过程中需要生成条形码,生成条形码可参考:https://www.cnblogs.com/linbky/p/12091248.html 下面这段代码生成的快递单是完全符合京东快递的10 x 1 ...
- Dwz/Jquery--使用Ajax提交表单时调用表单设置的校验
案例 今天有一个需求就是点击按钮时,使用ajax方式提交表单,而且不是直接用form表单下的submit按钮提交,表单中用的校验是dwz 自带的校验方式,表单模板如下: <li><d ...
随机推荐
- KnockoutJS 3.X API 第四章 表单绑定(12) selectedOptions、uniqueName绑定
selectedOptions绑定目的 selectedOptions绑定控制当前选择多选列表中的哪些元素. 这旨在与<select>元素和选项绑定结合使用. 当用户选择或取消选择多选列表 ...
- JAVA-集合作业-已知有十六支男子足球队参加2008 北京奥运会。写一个程序,把这16 支球队随机分为4 个组。采用List集合和随机数
第二题 已知有十六支男子足球队参加2008 北京奥运会.写一个程序,把这16 支球队随机分为4 个组.采用List集合和随机数 2008 北京奥运会男足参赛国家: 科特迪瓦,阿根廷,澳大利亚,塞尔维亚 ...
- 通过telnet来实践HTTP协议。
这是一篇实践教程,能够让你更加深刻的理解HTTP协议,因此需要一定的HTTP基础. 协议:一种规定,规定了你应该怎么去做,如w3c规定了浏览器应该怎么去解析HTML,CSS,JS.而HTTP则规定了客 ...
- Shader LOD
设置:单个设置Shader.maximumLOD.全局设置Shader.globalMaximumLOD.QualitySettings里面的Maximum LODLevel 原理:小于指定值的sha ...
- js中关于value的一个小知识点(value既是属性也是变量)
今天在学习input的value值时,发现这么一个小知识点,以前理解不太透彻. [1]以下这种情况是常见情况,会弹出“测试内容” <input type="button" v ...
- 文本溢出text-overflow和文本阴影text-shadow
前面的话 CSS3新增了一些关于文本的样式,其中text-overflow文本溢出和text-shadow文本阴影有些特别.因为它们有对应的overflow溢出属性和box-shadow盒子阴影属性. ...
- Python编码问题整理
认识常见编码 GB2312是中国规定的汉字编码,也可以说是简体中文的字符集编码 GBK 是 GB2312的扩展 ,除了兼容GB2312外,它还能显示繁体中文,还有日文的假名 cp936:中文本地系统是 ...
- [emacs] Drawing uml under emacs org-mode using plantUML - 类图
[emacs] Drawing uml under emacs org-mode using plantUML - 类图 // */ // ]]> [emacs] Drawing uml u ...
- Azure Automation (3) 定期将某个Azure订阅下的所有虚拟机开关机
<Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的Azure China. 在笔者之前的文章中,我们介绍了使用Azure Automation ...
- SQL Server代理(2/12):作业步骤和子系统
SQL Server代理是所有实时数据库的核心.代理有很多不明显的用法,因此系统的知识,对于开发人员还是DBA都是有用的.这系列文章会通俗介绍它的很多用法. SQL Server代理作业有一系列的一个 ...