个人理解
定义:定义一种操作的算法骨架,而将一些步骤延迟到子类中。延迟方法使得子类可以不改变一个算法结构即可重定义该算法的某些特定步骤。在模板模式中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
模板模式的基本构造:一个模板抽象类、至少一个继承模板抽象类的实体类。
模板模式中,模板抽象类将模板的大体骨架做好,但某些具体的可变实现代码将扩展至子类中进行,当使用场景发生变化时,可根据场景进行变换子类。个人感觉模板模式结合策略模式、简单工厂模式(或工厂模式)使用效果更佳。
案例分析
设计场景
某B2C平台后期制定方案,需要对用户进行标签化管理,根据用户的退货率、好评率对每个用户制定标签,便于筛选出优质客户(自己瞎想出来的场景,没有经过实践)。
遇到的问题
目前存在的问题是由于前期规划不彻底,导致用户来源并不是统一的(QQ登录、微博登录、手机号登录三种来源),而且没有限制用户必须绑定手机号或者其他相同的唯一信息(在B2C平台上不强制限制绑定手机号的情况我没见过,完全只是场景需要)。
解决方案
在这种情况下,使用模板抽象类定义根据退货率、好评率设定标签的逻辑代码,而获取退货率、好评率的逻辑代码则可以扩展到三个不同的子类中。
模板抽象类:
<?php
abstract Class Label
{
public function getLabel($sign)
{
$returnRate = $this->getReturnRate($sign);
if ($returnRate>=0.9) {
return '恶意用户';
} elseif ($returnRate<0.9 && $returnRate>=0.7) {
return '难缠用户';
} elseif ($returnRate<0.7 && $returnRate>=0.5) {
return '要求较高的用户';
} elseif ($returnRate<0.5 && $returnRate>=0.3) {
return '严格用户';
} else {
return $this->parsePraise($sign, $returnRate);
}
}
protected function parsePraise($sign, $returnRate)
{
$praiseRate = $this->getPraiseRate($sign);
if ($praiseRate>=0.8) {
return '刷单用户';
} elseif ($praiseRate<0.8 && $praiseRate>=0.5) {
return '拟刷单用户';
} else {
if ($returnRate>=0.1) {
return '正常用户';
} else {
return '好骗用户';
}
}
}
abstract protected function getReturnRate($sign);
abstract protected function getPraiseRate($sign);
}
QQ用户获取标签的类:
<?php
Class LabelQQ extends Label
{
protected function getReturnRate($sign)
{
//TODO::通过QQ号查找用户的退货率
return 0.25;
}
protected function getPraiseRate($sign)
{
//TODO::通过QQ号查找用户的好评率
return 0.8;
}
}
微博用户获取标签的类:
<?php
Class LabelWeibo extends Label
{
protected function getReturnRate($sign)
{
//TODO::通过微博ID查找用户的退货率
return 0.32;
}
protected function getPraiseRate($sign)
{
//TODO::通过微博ID查找用户的好评率
return 0.21;
}
}
手机号注册用户获取标签的类:
<?php
Class LabelPhone extends Label
{
protected function getReturnRate($sign)
{
//TODO::通过手机号查找用户的退货率
return 0.80;
}
protected function getPraiseRate($sign)
{
//TODO::通过手机号查找用户的好评率
return 0.10;
}
}
客户端调用代码:
<?php
include './Label.php';
include './LabelQQ.php';
include './LabelWeibo.php';
include './LabelPhone.php';
Class Client
{
public function main()
{
//获取某个QQ用户的标签
$labelQQ = new LabelQQ();
echo $labelQQ->getLabel('QQ号');
echo '<hr/>';
//获取某个微博用户的标签
$labelWeibo = new LabelWeibo();
echo $labelWeibo->getLabel('微博ID');
echo '<hr/>';
//获取某个手机号注册用户的标签
$labelPhone = new LabelPhone();
echo $labelPhone->getLabel('手机号');
}
}
$client = new Client();
$client->main();
案例UML图
之前一直用umlet做UML图,感觉效果不佳,现在这个使用StarUML做出来的,推荐一下。
下一篇
初识设计模式——外观模式