设计模式专题(七)——建造者模式
设计模式专题(七)——建造者模式
(原创内容,转载请注明来源,谢谢)
一、概述
建造者模式(Builder),又称生成器模式,是将一个复杂的对象的构建与它的表示进行分离,使得同样构建的过程可以获取不同的表示,即可以通过构建过程中输入的参数不同,获取不同的构建结果,但是构建出来的内容必须包含的元素一定会存在。
使用建造者模式,用户只需要输入建造类型,就可以获取所需要的结果,而不用关心具体的构造细节。这样做的好处在于,当实现某个内容,需要的操作步骤很多,就可以通过建造者模式来进行统筹控制,而不会遗漏、错误使用某些过程。
二、类图
三、优点
1、封装性,使用建造者模式可以使客户端不必知道服务端的实现细节。
2、建造者独立,容易扩展。
3、便于控制细节风险,由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
四、对比
1、建造者模式与工厂模式
与工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类——导演类。
因此,工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。
2、建造者模式与装饰模式
两者最根本的区别,在于装饰模式是用户可以对装饰的流程进行管控,根据需要进行不同的装饰,即需要在客户端对结果进行装饰;建造者模式更像是提供接口,根据客户端传入的建造方式,而调用服务端内部已经定义好的既定流程,返回一个建造的结果。
装饰模式的工作流程变化性更大,并且没有固定的建造流程,而是根据需要去进行“装饰”。而建造者模式,对于执行流程有比较固定的要求,虽然允许先后执行顺序不同、传入参数不同,但是大体上还是会构建出相似的结果。
因此,当添加(职能)的时候,可以用装饰模式。而当需要按照既定程序完成任务时,则考虑采用构建者模式。
五、使用场景
执行顺序——由于建造者模式是在建造者类中,根据客户端要求,进行各步骤的操作。因此,当同样的操作,不同的先后顺序,会得到不一样的结果,则可以用建造者模式。
1、实现业务
现要实现数据库的增删改操作(查询操作和增删改不太一样,因此不在放在此建造者模式中),则可以将三个操作封装在不同的方法中,并且调用一个建造者实现操作过程。
1)公共的操作,固定的流程
无论增删改的哪一种,都会按照下面的流程执行:
a.判断数据库连接情况,如果没有连接则连接数据库
b.拼接sql
拼接sql为三种操作有所区别的地方,但也有相同的地方可以提取,包括确定表格,确定where条件(修改和删除需要),确定改动字段(新增和修改需要),确定改动的值(新增和修改需要)
c.执行sql,并获取返回结果(新增返回last_insert_id,修改和删除返回affect_rows)
d.判断执行结果,如果成功,将sql语句、操作人员、操作时间记录数据库操作日志;如果失败,将失败的报错信息、sql语句、操作时间、操作人员记录数据库错误日志。
f.如果需要数据库操作的原子性,则事务操作beginTransaction和commit、rollback也是公共的操作。
2)独有的操作
a.新增
新增需要传入一个数组,包括字段和新增后的值的对应关系。
b.修改
修改需要传入两个数组,一个数组是类似新增的,字段和修改后的值的对应关系;另一个是where条件数组,包括字段和对应的where条件。
c.删除
删除需要传入一个数字,类似修改的where数组,包括字段和对应的where条件。
d.互不相同之处
拼接的sql语法不同。
2、实现方式
<?php
//建造者模式
//建造者抽象类,定义规则
abstract class SqlBuilder{
public function__construct($type, array $arrData1=array(), array $arrData2=array()){}
public functiongetConnection($server='localhost', $username='root', $password='root',$database='test'){}
private functionbindSql($query, $arrData){}
public functioninsert($table, array $arrData){}
public functionupdate($table, array $arrData, array $arrWhere){}
public functiondelete($table, array $arrWhere){}
public functionstartTrans(){}
public functioncommitTrans(){}
public functionrollbackTrans(){}
}
//mysql实现的建造者
public function MysqlBuilder extends SqlBuilder{
private $type;
private $arrData;
private $arrWhere;
private $table;
//根据传入的类型进行操作
public function__construct($type, $table, array $arrData1, array $arrData2=array()){
switch($type){
case'insert':
$this->arrData= $arrData1;
break;
case'update':
if(empty($arrData2)){
returnnull;
}else{
$this->arrData= $arrData1;
$this->arrWhere= $arrData2;
}
break;
case'delete':
$this->arrWhere= $arrData1;
break;
default:
returnnull;
break;
}
}
//连接数据库
public functiongetConnection($server='localhost', $username='root', $password='root',$database='test'){
$dbConnection= new PDO('mysql:host='.$server.';dbname='.$database.'',$username,$password);
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$this->conn= $dbConnection;
return$this;
}
//绑定值
private functionbindSql($query, $arrData){
if(empty($arrData)){
returnnull;
}else{
foreach($arrDataas $col => &$val){
$col= ':'.$col;
$query->bindParam($col,$val);
}
return$query;
}
}
//增删改的具体过程省略
public functioninsert(){
//....
}
public functionupdate(){
//...
}
public functiondelete(){
//...
}
//事务处理
public functionstartTrans(){
$this->conn->beginTransaction();
return$this;
}
public functioncommitTrans(){
$this->conn->commit();
return$this;
}
public functionrollbackTrans(){
$this->conn->rollback();
return$this;
}
}
//指挥者,负责完成操作
class Director{
public function__construct(SqlBuilder $builder){
$type =$builder->type;
$builder =$builder->getConnection()->startTrans();
switch($type){
case'insert':
$builder->insert();
break;
case'update':
$builder->update();
break;
case'delete':
$builder->delete();
break;
default:
$builder->rollbackTrans();
returnnull;
break;
}
$builder->commit();
}
}
//客户端,获取产品
$insertSql = new MysqlBuilder('insert', 'test',array('col1'=>'val1'));
$res = new Director($insertSql);
三、评价
建造者模式,实现客户端通过输入类型以及一些参数,获取建造的结果,而屏蔽各类细节。既可以规范的控制建造流程,又简化客户端的操作。
但是,实际项目中,通常数据库的增删改的操作,用到PHP的工作单元的知识,另外还涉及标记映射的知识。这块的内容是项目最常用到的方式,近期将针对数据库的增删改操作,运用工作单元的方式,进行项目级的实现。
——written by linhxx 2017.08.01
相关阅读:
设计模式专题(六)——原型模式
设计模式专题(五)——工厂方法模式
设计模式专题(四)——代理模式
设计模式专题(三)——装饰模式
设计模式专题(二)——策略模式
设计模式专题(一)——面向对象的设计原则
- 这么多前端优化点你都记得住吗?
- 愚蠢的”记住“密码方式终于还是出了问题
- C#获取本机可用端口
- 想知道你的对象用微信和谁聊得最多吗?一个代码告诉你
- objective-C中的接口与泛型
- 段永朝:天性,互联网的灵性回归
- objective-C中的Class(类类型),Selector(选择器SEL),函数指针(IMP)
- 数据中心进水了怎么办?数据中心如何防洪?
- 戴若犁:虚拟中的现实
- kvm虚拟化管理平台WebVirtMgr部署-完整记录(1)
- objective-C中如何判断一个类中有没有定义某个方法
- Steve Boswell:智能口罩让PM2.5滚蛋
- kvm虚拟化管理平台WebVirtMgr部署-完整记录(2)
- objective-C中的扩展方法与partial class
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python中使用马尔可夫决策过程(MDP)动态编程来解决最短路径强化学习问题
- 《剑指 offer》刷题记录之:树 & 栈和队列
- R语言自定义两种统计量度:平均值和中位数,何时去使用?
- 设计模式之适配器模式
- 自然语言处理中的预训练模型(上)
- numpy数组中冒号和负号的含义
- 基于R语言实现LASSO回归分析
- PHP预防XSS攻击,ajax跨域攻击的方法
- PHP中利用header设置content-type和常见文件类型的content-type
- 《剑指 offer》刷题记录之:递归和循环
- PHP缓存技术介绍
- R语言画ROC曲线总结
- PHP中$_SERVER的详细参数
- R语言使用贝叶斯层次模型进行空间数据分析
- PHP中的小数取整