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 ...
随机推荐
- OpenCascade Tcl vs. ACIS Scheme
OpenCascade Tcl vs. ACIS Scheme eryar@163.com 摘要Abstract:本文通过OpenCascade的Tcl/Tk和ACIS的Scheme的对比来说明脚本语 ...
- Android线程之主线程向子线程发送消息
和大家一起探讨Android线程已经有些日子了,谈的最多的就是如何把子线程中的数据发送给主线程进行处理,进行UI界面的更新,为什么要这样,请查阅之前的随笔.本篇我们就来讨论一下关于主线程向子线程如何发 ...
- svn 合并分支代码到主干
1. eclipse 安装subclipse 2. 将主干trunk导入到eclipse中 3. 右键选择team-->合并,注意,去掉红色圈内的选项 4. next 选中select查找svn ...
- Sybase 数据库新增用户,赋权
Sybase数据库, 需求:新增用户user1,赋予对原数据库中表t_jingyu的查询权限 数据库原用户登陆 isql -U用户 -P密码 -S服务名 sp_addlogin 'user1','us ...
- Windows Azure Active Directory (3) China Azure AD增加新用户
<Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的China Azure. 本文是对笔者之前的文档:Windows Azure Active ...
- [Java 基础]数组
数组初始化 定义数组语法格式 定义数组有两种方式,如下两种格式是等价的: int[] a1; int a1[]; 注:在C/C++中,不支持第一种格式.但是,推荐使用这种方式,因为这样似乎更合理,声 ...
- 深度浅出immutable.js
这篇文章将讲述immutable.js的基本语法和用法. 1.fromJs() Deeply converts plain JS objects and arrays to Immutable Ma ...
- 30天C#基础巩固------面向鸭子编程,关于string和File的练习
面向对象编程就是面向抽象的父类进行编程,具体的实现不用考虑,由子类决定.<经典的说法--面向鸭子编程> eg:鸭子的编程,<对于多态的理解> 我们都习惯把使用 ...
- chm转换为html的超简单方法
在Windows下chm转换为html的超简单方法(反编译CHM文件的方法) 通过调用Windows命令,将chm 文件转换为html 文件. 方法: 命令行(cmd),输入hh -decompile ...
- Mailbox unavailable. The server response was: 5.1.1 User unknown
昨晚至今早,在新的项目中,实现一个小功能,就是当有访问者浏览网页在留言簿留言时,系统把留言内容发送至某一个邮箱或是抄送指定的邮箱中. 使用以前能正常发送邮件的代码,但在新项目中,测试时,就是出现标题的 ...