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 ...
随机推荐
- PL/SQL异常处理
As we all known,程序的错误一般分为两类:编译错误和运行时错误.其中运行时错误被称为异常.PL/SQL语句块中处理异常的部分即为异常处理部分.在异常处理部分,可以指定当特定异常发生时所采 ...
- 队列的存储结构和常见操作(c 语言实现)
一.队列(queue) 队列和栈一样,在实际程序的算法设计和计算机一些其他分支里,都有很多重要的应用,比如计算机操作系统对进程 or 作业的优先级调度算法,对离散事件的模拟算法,还有计算机主机和外部设 ...
- Foundation 5 发布!最先进的响应式前端框架
数以百万计的设计师和工程师采用 Foundation 作为他们的产品和网站设计的前端框架.Foundation 是第一个响应式.语义化和移动优先的开源框架.最新发布的 Foundation 5 是最先 ...
- 【Android】Android Camera实时数据采集及通过MediaCodec硬编码编码数据的流程
吐槽: 其实常用流程都差不多,但是有时候还是会忘记某一步的详细用法,但是各位朋友请注意,官方已经不推荐Camera类的使用(现在是android.hardware.camera2),但无奈公司项目之前 ...
- 【原创】利用typeface实现不同字体的调用显示及String转换为Unicode
最近工作用到,就写个小demo demo实现从assets中利用typeface调用不同字体,并在editText中显示出来 1.layout中创建activity_main.xml文件 布局代码如下 ...
- js单击输入框后弹出提示信息效果
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 使用junit测试用例
通常只会使用junit测试非main方法,在我眼里就是程序入口实现而已.今天,发现原来可以测试类. 针对mybatis练习.在需要测试的UserDaoImpl类上右键,新建一个junit case,位 ...
- 设计宝库:22套精美的 PhotoShop 素材免费下载
<设计宝库>系列给大家带来22套精美的 PSD 设计素材,你可以免费下载使用.设计师经常会去网上搜罗各种各样的素材,这些免费素材不仅能帮助他们节省大量的时间,而且能有很好的效果.非常感谢那 ...
- 精美素材:40个漂亮的 PSD 贴纸模板《上篇》
贴纸经常被网页设计师用于为标注网站中的不同元素,以此吸引访客的注意.此外,使用贴纸也使网站更具吸引力.虽然设计者可以使用 Photoshop 制作贴纸,但他们也可以利用从互联网上下载现成的模板.这些模 ...
- 【手把手教你全文检索】Lucene索引的【增、删、改、查】
前言 搞检索的,应该多少都会了解Lucene一些,它开源而且简单上手,官方API足够编写些小DEMO.并且根据倒排索引,实现快速检索.本文就简单的实现增量添加索引,删除索引,通过关键字查询,以及更新索 ...