在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
关键代码:实现同一个接口。
优点:
1、算法可以自由切换。
2、避免使用多重条件判断。
3、扩展性良好。
缺点:
1、策略类会增多。
2、所有策略类都需要对外暴露。
使用场景
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2、一个系统需要动态地在几种算法中选择一种。
3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
情人节已到,男孩子需要为老婆(女朋友)准备礼物。
思来想去,给我老婆准备一束玫瑰花
/**
* 玫瑰花
*/
class Rose
{
//外观
public string $appearance = "美丽";
//寓意
public string $moral = "爱情";
}
能过这个节日只有我们人类
/**
* 人类
*/
interface PersonalInterface
{
public function getName();
public function getAge();
}
/**
* 人类实体
* */
class Personal implements PersonalInterface
{
public string $name;
public string $age;
public function __construct(string $name,int $age)
{
$this->setName($name);
$this->setAge($age);
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @return string
*/
public function getAge(): string
{
return $this->age;
}
/**
* @param string $age
*/
public function setAge(string $age): void
{
$this->age = $age;
}
}
这个美丽的节日肯定是我和老婆一起过
/**
* 男人
*/
class ManPersonal extends Personal
{
//搞n朵玫瑰花
public function createMissile(int $num) : array
{
$arr = [];
for($i=0;$i<$num;$i++)
array_push($arr,new Rose());
return $arr;
}
}
/**
* 女人
*/
class WomanPersonal extends Personal
{
public function revMissile(array $roses) : string
{
//情景1 - 多个鲜花当中混了一束假花
foreach($roses as $rose)
{
if(!($rose instanceof Rose))
return "渣男,送花还要送假花";
}
//鲜花总数量
$sumRose = count($roses);
//女生心仪数量集合
$womanFavorite = [
666,99,88,999
];
//情景2 - 鲜花数量不够
if($sumRose < 10)
return "渣男,就这么几朵花就想打动我";
//情景3 - 鲜花数量在 10-30朵内
if($sumRose > 10 && $sumRose<30)
return "流氓,勉强过关";
//情景3 - 鲜花数量在某个区间值
if($sumRose > 30 && !in_array($sumRose,$womanFavorite))
return "宝宝肯定很爱我";
//情景4 - 真爱
if(in_array($sumRose,$womanFavorite))
return "这就我的真命天子吗?";
return "渣男";
}
}
美丽的节日有很多
/**
* 节日
*/
interface FestivalInterface
{
}
/**
* 情人节 - 策略模式实现
*/
class ValentineDay implements FestivalInterface
{
public array $personals = [];
public function __construct(PersonalInterface ...$args)
{
if(!empty($args))
array_push($this->personals,...$args);
}
public function __call(string $methodName,array $params)
{
if(!empty($this->personals))
{
foreach($this->personals as $personal)
{
if(method_exists($personal,$methodName))
{
return $personal->{$methodName}(...$params);
}
}
}
throw new \Exception('not exec',101);
}
}
开始行动,看看我给老婆送花会有什么结果
//男人
$man = new ManPersonal('谭勇',27);
//女人
$woman = new WomanPersonal('王玉梅',26);
//情人节到了
$festival = new ValentineDay($man,$woman);
//准备1朵玫瑰花
$missiles = $festival->createMissile(1);
//把玫瑰花送给老婆
$result = $festival->revMissile($missiles);
var_dump($result);//渣男,就这么几朵花就想打动我
//准备19朵玫瑰花
$missiles = $festival->createMissile(19);
//把玫瑰花送给老婆
$result = $festival->revMissile($missiles);
var_dump($result);//流氓,勉强过关
//准备56朵玫瑰花
$missiles = $festival->createMissile(56);
//把玫瑰花送给老婆
$result = $festival->revMissile($missiles);
var_dump($result);//宝宝肯定很爱我
//准备999朵玫瑰花
$missiles = $festival->createMissile(999);
//把玫瑰花送给老婆
$result = $festival->revMissile($missiles);
var_dump($result);//这就我的真命天子吗?
男孩子要时常关心和保护女孩子
既然要找工作,那么必须是人找工作
/**
* 人类
*/
interface PersonalInterface
{
/**
* 是否合适这个工作
* @return boolean true=>适合这个工作 false=>不适合这个工作
*
public function adaptation(Work $work);
}
/**
* 人类实体
*/
abstract class Personal implements PersonalInterface
{
public function __construct(
public string $name,
public int $age
){}
}
/**
* 男人
*/
class ManPersonal extends Personal
{
public function adaptation(Work $work)
{
if($work instanceof MoveBricks)
return true;
return false;
}
}
/**
* 女人
*/
class WomanPersonal extends Personal
{
public function adaptation(Work $work)
{
if($work instanceof Waiter)
return true;
return false;
}
}
设计一个抽象类:工作。作为所有工作的抽象父类
目前提供有搬砖、服务员两个工作
/**
* 工作
*/
interface Work
{
public function getName();
}
/**
* 搬砖
*/
class MoveBricks implements Work
{
public function getName()
{
return "搬砖工作";
}
}
/**
* 服务员
*/
class Waiter implements Work
{
public function getName()
{
return "服务员工作";
}
}
设计一个招聘中心
/**
* 找工作服务
*/
class JobHunting
{
public array $works = [];
public function __construct(Work ...$args)
{
array_push($this->works,...$args);
}
public function job(PersonalInterface $personal) : Work
{
if(!empty($this->works))
{
foreach($this->works as $work)
{
if($personal->adaptation($work))
return $work;
}
}
throw new Exception("没有匹配的工作",101);
}
}
开始找工作
//初始化找工作服务,将已有的招聘工作注册进去
$jobService = new JobHunting(new MoveBricks(),new Waiter());
//实例化一个人
$man = new ManPersonal('谭勇',27);
//获得工作
$manWork = $jobService->job($man);
//输出工作名称
echo $manWork->getName(); //搬砖