原文地址: 【技术文章】《记一次意外的技术讨论收获—策略模式》
本文地址:https://www.cnblogs.com/aiweixiao/p/9460933.html
扫描关注公众号
最近公司有和第三方合作的项目,于是想到了使用策略模式去实现,到时候有别的第三方来走他自己的策略去完成相关的业务流程就行了。
gitHub地址: http://t.cn/RDO9luX
1)类加载的问题--命名空间
但是我们在做的过程中遇到的第一个问题就是命名空间的问题,因为公司老的框架是不支持也没有使用命名空间的,我仿照之前的一个业务实现的策略,在一个php文件中有多个类文件,但是使用了php的命名空间之后,外部就调用不到这些类了,否则是多个类,命名多个命名空间,但是因为新框架使用的自动加载是默认文件名和类名是一致的,否则也是不好加载进来。于是想到了拆分类,将基类BaceStrategyClass,BaceCooperationClass,接口Interface,和工厂类ClassFactory放到了一个文件ClassFactory.php中,将与第三方进行连接交互的类Cooperation放到了一个文件xxxCooperatioin.php中,还有一个这次合作的策略类XXXStrategy 放到了一个文件XXXStrategy.php中,这样就解决了类加载的问题。
1 <?php 2 //测试脚本 3 include_once("init.php"); 4 use \Strategy\FacultyClass; 5 6 7 //1.工厂类是唯一入口,构造方法返回的是类自己实例 8 $res = (new FacultyClass('XXX'))->strategyName->testStrategy('Hello', 'World');//echo Hello World 9 10 //2.走单例模式 11 //$res = FacultyClass::getStrategyInstance('XXX')->testStrategy('Hello', 'World');//echo Hello World 12 13 //3.直接访问 XXXStrategy 不行,错误是 Class 'Strategy\BaseStrategyClass' not found 14 //$res = new XXXStrategy();
2)公司内部外系统的访问—层级调用
我们遇到了第二个问题就是我们这个系统需要公司其他系统,比如用户系统的数据,但是新框架定义与公司外系统的交互,都在service层完成,领域层domian中只完成与自己系统业务相关的内容,所以为了符合层级调用和符合规范,就将这些domian中的策略整体进行了迁移,重新定义了命名空间,也修改了相关地方的调用的命名空间类use引用。
1 <?php 2 namespace Strategy; 3 4 //工厂类 5 class FacultyClass 6 {/*{{{*/ 7 public $strategyName; 8 public function __construct($strategyName) 9 { 10 $strategyClass = 'Strategy\\'.$strategyName.'Strategy'; 11 $this->strategyName = new $strategyClass; 12 return $this->strategyName;//外部接收不到这个,还是工厂类自己的实例 13 } 14 15 public static function getStrategyInstance($strategyName) 16 { 17 static $ins; 18 $strategyClass = 'Strategy\\'.$strategyName.'Strategy'; 19 //单例模式 20 if(false == $ins instanceOf $strategyClass) 21 { 22 $ins = new $strategyClass; 23 } 24 25 return $ins; 26 } 27 }/*}}}*/ 28 29 //策略基类 30 class BaseStrategyClass 31 { 32 33 } 34 35 //第三方交互基类 36 class BaseCooperationClass 37 { 38 39 } 40 41 42 //策略接口 43 interface IStrategy 44 { 45 public function testStrategy($argsOne, $argsTwo); 46 }
3)必须走工厂方法—唯一入口,封装性
然后我们遇到的第三个问题是,之前都是通过工厂方法的构造方法,将策略类的实例作为其属性,使用 (new classFaculty(‘xxx’))->strategyClass 得到策略实例,然后这个策略实例里,可以调用 xxxCooperatioin类中的相关方法,这个是可以走通的,但是如果我只是想测试 xxxCooperatioin类中的方法,就不行,包括测试xxxStrategy类中的方法都是不行的,都分别报 不存在其 基类 BaceCooperationClass 和BaceStrategyClass不存在,这个就比较尴尬了,百思不得其解,我和潇同学“抓耳挠腮”,再仔细看看 三个文件 ClassFactory.php , xxxCooperatioin.php 和 XXXStrategy.php, 终于发现原来走工厂那种访问的时候,ClassFactory.php 中已经包含了 xxxCooperatioin 类和xxxStrategy类所需要的基类了,所以一路走下来,是可以加载各个类的,但是如果是 直接外部测试脚本调用 xxxCooperatioin类 和xxxStrategy类是不行的,因为他们的基类在 ClassFactory.php中,而你又无法使用命名空间将其加载进来(因为BaceCooperationClass 和BaceStrategyClass 和文件ClassFactory.php的文件名不一样,无法加载),这样就强制外部必须走工厂ClassFactory类 来访问到 xxxCooperatioin类,和xxxStrategy类,这样就提高了安全性,实现了封装性。
1 <?php 2 namespace Strategy; 3 4 5 //XXXStrategy 具体策略类 6 class XXXSt