设计模式之策略模式

简介

1. 策略模式,将一组特定的行为和算法封装成类,以适应某些特定的上下文环境,这种模式就是策略模式。
2. 实际应用举例,假如一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且显示对应的广告位。
3. 使用策略模式可以实现依赖倒置 , Ioc , 控制反转。

传统的做法应该是使用 if 这种分支的接口,每增加一个条件,所有使用到了分支语句的地方都需要修改!但是这是一种「硬编码」的方法。

使用了策略模式,它与上下文的环境完全是中立的,完全不依赖。像上面的例子中,如果新增了一种条件,只需要新添加1个策略即可,其他地方应用该策略即可。

创建策略的接口文件(Think\UserStrategy.php)

1
2
3
4
5
6
7
8
namespace Think

//定义一个用户的策略接口
interface UserStrategy
{
function showAd();
function showCategory;
}

策略实现

分别实现 女士用户的策略,男士用户的策略

女士策略(Think\FemaleUserStrategy.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace Think;

class FemaleUserStrategy implements UserStrategy
{
function showAd()
{
echo "2017新款女装";
}

function showCategory()
{
echo "女装目录";
}
}

男士策略(\Think\MaleUserStrategy.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace Think;

class MaleUserStrategy implements UserStrategy
{
function showAd()
{
echo "电子产品";
}

function showCategory()
{
echo "3C配件目录";
}
}

传统实现(index.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 入口文件
define('BASEDIR', __DIR__);
include BASEDIR . '/Think/Loder.php';
spl_autoload_register('\\Think\\Loder::autoload');

class Page
{
function index()
{
// 首页显示
if ($_GET['m'] == "female") {
# code...
} elseif ($_GET['m'] == "male") {
# code...
} else {
//
}
}
}

$page = new Page();
$page->index();

传统的方法需要写这些条件分支语句,才能实现需求,但是不足之处在于一旦需要增加条件,那么所有使用到这些分支的地方都需要修改。

使用策略模式(index.php)

设置策略的方法

1
2
3
4
function setStrategy(Think\UserStrategy $strategy)
{
$this->strategy = $strategy;
}

该方法 约定了接口的类型 为:UserStrategy。

根据条件 来实例化策略,并把对象传递给 Page类

1
2
3
4
5
6
7
8
// 根据条件实例化对应的策略
if (isset($_GET['m']) && $_GET['m'] == 'female') {
$strategy = new Think\FemaleUserStrategy();
} else {
$strategy = new Think\MaleUserStrategy();
}
// 把策略的对象,传递到页面的对象中
$page->setStrategy($strategy);

最后代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 入口文件
define('BASEDIR', __DIR__);
include BASEDIR . '/Think/Loder.php';
spl_autoload_register('\\Think\\Loder::autoload');

class Page
{
protected $strategy;
function index()
{
// 这里不需要使用分支结构,直接调用策略的对象的实现方法
$this->strategy->showAd();
$this->strategy->showCategory();
}

// 设置策略的方法
function setStrategy(Think\UserStrategy $strategy)
{
$this->strategy = $strategy;
}
}

$page = new Page();

// 根据条件实例化对应的策略
if (isset($_GET['m']) && $_GET['m'] == 'female') {
$strategy = new Think\FemaleUserStrategy();
} else {
$strategy = new Think\MaleUserStrategy();
}
// 把策略的对象,传递到页面的对象中
$page->setStrategy($strategy);
$page->index();
纵有疾风起,人生不言弃!