转载请注明作者和出处://www.greatytc.com/p/fceff41be9d1
运行平台: Windows
php版本: php7.0
策略模式,简单来说,就是完成不同的的任务,却用相同的方法来实现,我们可能见过用到策略模式的地方就是php框架中,封装了针对不同数据库的方法,可是我们却都能用同一种方法调用他们,我是这么理解的,如果有什么错误的地方欢迎指正。
- 环境角色(Context):持有一个Strategy的引用
- 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体的策略类所需的接口
- 具体策略(ConcreateStrategy)角色:包装了相关的算法或行为
常用英文单词:Strategy,Context
最好把设计模式常用的英文单词用熟,这样在你阅读源代码的时候有很大的帮助,往往大神写的代码注释很少,但是他们的变量名,方法名都符合规范,你看到这个单词就知道是怎么一回事,这比无用的注释好了很多
//定义一个规范,抽象策略类
abstract class Strategy{
//小明上学的方法
abstract function Way();
}
//骑自行车类
class BikeStrategy extends Strategy{
public function Way()
{
echo "骑自行车上学咯";
}
}
//小车类
class CarStrategy extends Strategy{
public function Way()
{
echo "开车上学咯";
}
}
//走路上学类
class WalkStrategy extends Strategy{
public function Way()
{
echo "走路上学咯";
}
}
class SchoolContext{
private $strategy;//获取具体策略
public function __construct(Strategy $strategy)//参数设定为继承Strategy接口的子类
{
$this->strategy= $strategy;
}
public function useRun(){
$this->strategy->Way();
}
}
$school = new SchoolContext(new BikeStrategy());
$school->useRun();//骑自行车上学咯
$school = new SchoolContext(new WalkStrategy());
$school->useRun();//走路上学咯
这里我们把实例化的类作为一个参数注射(依赖注入,内部方法的实现依赖于外部实例化类)进入到学校类之中,我们使用类 Strategy $strategy 限制类必须为继承Strategy接口的子类,这样可以有效防止注入大炮火箭之类乱七八糟的东西,好了,那么我们看看策略模式的一些实际应用场景。
<?php
//分享类抽象接口
abstract class ShareStrategy{
//分享的标题
abstract function share_title();
//分享的作者
abstract function share_author();
//分享的文章
abstract function share_content();
}
//微信分享
class WechatShareStrategy extends ShareStrategy{
//分享的标题
public function share_title(){
//标题
}
//分享的作者
public function share_author(){
//作者
}
//分享的文章
public function share_content(){
//文章
}
}
//qq分享
class QQShareStrategy extends ShareStrategy{
//分享的标题
public function share_title(){
//标题
}
//分享的作者
public function share_author(){
//作者
}
//分享的文章
public function share_content(){
//文章
}
}
class ShareContext{
private $strategy;//保存对象
public function __construct(ShareStrategy $strategy)//参数设定为继承Strategy接口的子类
{
$this->strategy = $strategy;
}
public function title(){
$this->strategy->share_title();
}
public function author(){
$this->strategy->share_author();
}
public function content(){
$this->strategy->share_content();
}
}
class ShareFactory{
static public function factory($strategy){
switch($strategy){
case 'wechat':
$object = new WechatShareStrategy();
break;
case 'qq':
$object = new QQShareStrategy();
break;
}
return $object;
}
}
class Article{
//分享
public function Share(){
$strategy = ShareFactory::factory('wechat');
$shareContext = new ShareContext($strategy);
$shareContext->title();//微信分享标题
$shareContext->author();//微信分享作者
$shareContext->content();//微信分享内容
}
}
我们这里结合上一章所学的简单工厂实现了一个分享的简单例子,当然,简单工厂也有局限性,就是我们每次增加一个分享类,就要去工厂里增加方法,破化了类的开放封闭原则,我们可以结合类的反射来修改一下ShareFactory方法;
<?php
//分享类抽象接口
abstract class ShareStrategy{
//分享的标题
abstract function share_title();
//分享的作者
abstract function share_author();
//分享的文章
abstract function share_content();
}
//微信分享
class WechatShareStrategy extends ShareStrategy{
//分享的标题
public function share_title(){
echo 'wechat_title'."\n";
//标题
}
//分享的作者
public function share_author(){
echo 'wechat_author'."\n";
//作者
}
//分享的文章
public function share_content(){
echo 'wechat_content'."\n";
//文章
}
}
//qq分享
class QQShareStrategy extends ShareStrategy{
//分享的标题
public function share_title(){
echo 'qq_title';
//标题
}
//分享的作者
public function share_author(){
echo 'qq_author';
//作者
}
//分享的文章
public function share_content(){
echo 'qq_content';
//文章
}
}
class ShareContext{
private $strategy;//保存对象
public function __construct(ShareStrategy $strategy)//参数设定为继承Strategy接口的子类
{
$this->strategy = $strategy;
}
public function title(){
$this->strategy->share_title();
}
public function author(){
$this->strategy->share_author();
}
public function content(){
$this->strategy->share_content();
}
}
class ShareFactory{
//返回实例化对象
static public function factory($strategy){
//$strategy为类的字符串名称
$class = new ReflectionClass($strategy);
return $class->newInstance();
}
}
class Article{
//分享
static public function Share(){
$strategy = ShareFactory::factory('WechatShareStrategy');
$shareContext = new ShareContext($strategy);
$shareContext->title();//微信分享标题
$shareContext->author();//微信分享作者
$shareContext->content();//微信分享内容
}
}
Article::Share();
输出结果
我们通过传入类的字符串名称,来进行动态的实例化类(在框架里一般还会配合spl_autoload_register()这个自动加载类来加载实现实例化类),关于这类实例化类还需要考虑构造函数的参数等等因素,我这里比较简单的提一下,有需要的可以去百度查找一下更详细的资料,或者以后在依赖注入这一章节会配合laravle核心ioc容器来详细讲解。