策略模式

它定义了算法家族, 分别封装起来, 让它们之间可以相互替换, 此模式让算法的变化, 不会影响到使用算法的客户。不同的策略都是完成相同的工作,只是实现不同, 它可以以相同的方式调用所有的算法, 减少了各种算法类与使用算法类之间的耦合。

UML结构图

image

  • Strategy 提供算法的抽象接口,图中它提供了一个AlgorithmInterface接口方法,让具体的策略类来实现该方法。Strategy类可以是接口也可以是抽象类。在策略类是抽象类的情况下,通常AlgorithmInterface方法也是抽象方法。
  • ConcreteStrategyA ConcreteStrategyB ConcreteStrategyC 分别是策略的具体实现。
  • Context 使用策略的上下文环境,通常称之为Context。

例子

在用户登录这个功能中经常需要对用户输入的密码进行加密,有时候我们使用MD5对用户密码进行加密,有可能后面需要换成HASH或其他加密算法。为了在发生需求变更的情况下不修改原来的代码。我们可以用策略模式来封装可变的部分,这也遵守了开放封闭原则(对修改关闭,对扩展开放)。

UML结构图

image

代码

加密策略接口
1
2
3
4
interface Encryption
{
function encrypt(string $value): string;
}
MD5加密策略的实现
1
2
3
4
5
6
7
class Md5Encryption implements Encryption
{
public function encrypt(string $value): string
{
return md5($value);
}
}
HASH加密策略的实现
1
2
3
4
5
6
7
class HashEncryption implements Encryption
{
public function encrypt(string $value): string
{
return hash($value);
}
}
上下文

账号登录的一个业务服务,也是我们策略模式中的Context。该服务通过依赖注入把我们的Encryption的具体实现注入到AccountLoginService中。当我们修改密码加密策略的时候,不再需要修改AccountLoginService,而是新写一个Encryption的实现,然后把该实现注入到AccountLoginService中即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class AccountLoginService
{
protected $encryption;

public function __construct(Encryption $encryption)
{
$this->encryption = $encryption;
}

public function login(string $username, string $password)
{
$encryptedPassword = $this->encryption->encrypt($password);
// ...
// 其他登录需要的逻辑,比如数据库查询等。
}
}

有时候我们希望在AccountLoginService的生命周期中需要替换策略实现的时候,只需要在AccountLoginService上加一个setEncryption方法即可。

1
2
3
4
5

public function setEncryption(Encryption $encryption)
{
$this->encryption = $encryption;
}
单例模式 OAuth2
You need to set install_url to use ShareThis. Please set it in _config.yml.

评论

You forgot to set the shortname for Disqus. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×