摘要:反射提供给面向对象编程可以自省的能力,即反射。在简单工厂模式中,根据传递的参数来返回不同的类的实例简单工厂模式又称为静态工厂方法模式。也就是简单工厂模式工厂工厂类。
利用反射来实现工厂模式的生产而无需创建特定的工厂类
转载请注明来源
[Relfection]
Reflection
Reflection
,即反射。反射提供给面向对象编程可以自省的能力PHP
提供了完整的反射 API
,提供了内省类、接口、函数、方法和扩展的能力。此外,反射 API
提供了方法来取出函数、类和方法中的文档注释。详细见PHP官网
PHP反射简介 Reflection
能干什么[protected/private]
,这些特性使得PHP的使用灵活性得到非常大的提高。例如:Laravel
框架的所谓优雅所在,即容器、依赖注入、IOC
控制反转就是依靠这些特性实现的Hyperf
框架的注解路由也是根据反射获得注释来实现的生成文档
因为反射可以获取类属性和方法的访问权限,可以扫描整个项目的所有文件再使用反射来生成文档测试驱动开发
利用反射获取该类的所有方法的特性,进行测试驱动开发开发插件
利用反射获取类的内部结构的特性,实现 Hook
功能,例如框架插件的实现Reflection
的优缺点优点
反射提供了对类的反解析,从而相比原本面向对象的编程方式获得了极高的灵活性,以及合理的使用能够让代码看起来更加优雅以及简洁。原本在面向对象的编程方式中,使用一个类的实例需要先 new
出一个对象再使用方法,但是使用了反射机制,只需要提供一个该类的方法然后使用反射机制即可使用该对象或者方法。Laravel
框架正是使用了大量的反射才获得了优雅的美誉,Swoole
的 Hyperf
框架的注解路由的实现也是使用了反射缺点
同时,由于反射是类实例化的反过程,破坏了面向对象的封装性,直接将类的整个内部结构暴露,这就导致了反射一旦滥用,代码将难于管理,整个项目将非常混乱,甚至导致业务执行错乱。尤其在大项目几十人的团队中,试想一下,原本的面向对象,只告诉什么可以用,什么不可以用,CTO写好了底层代码,其他人继承后然后使用就行,内部结构啥的其他人都不知道。一旦用上了反射,如果有一个程序员不小心将原本是 protected
或者是 private
的属性或者方法设置成了可以访问,其他程序员在不知情的情况调用了本该隐藏的数据或者方法,那将导致不可预测的灾难【见下面示例代码】IDE
中通过直接直接点击代码溯源,对于新手真的是很蛋疼,Laravel
和Hyperf
都是如此private
方法设置成外部可访问#Example:setAccessible(true);echo $method->invoke(new Foo);// echos "7"?>
[简单工厂模式] [工厂模式] [抽象工厂模式]
简单工厂模式
又称为静态工厂方法模式。简单的说,就是创建对象的方式是通过一个静态方法来实现的。在简单工厂模式中,根据传递的参数来返回不同的类的实例PHP
中在简单工厂模式中,有一个抽象的产品类【即abstract class Calculate
】,这个抽象类可以是接口/抽象类/普通类
。这个抽象的产品类可以派生出多个具体的产品类【即class CalculateAdd
以及class CalculateSub
】。最后再由一个具体的工厂类【即class CalculateFactory
】来获取所需要的产品类的实例//生产抽象类abstract class Calculate{ //数字A protected $number_a = null; //数字B protected $number_b = null; //设置数字A public function setNumberA( $number ){ $this->number_a = $number; } //设置数字B public function setNumberB( $number ){ $this->number_b = $number; } //获取数字A public function getNumberA(){ return $this->number_a; } //获取数字B public function getNumberB(){ return $this->number_b; } //获取计算结果【获取生产出的产品】 public function getResult(){ return null; }}
//加法运算class CalculateAdd extends Calculate{ //获取运算结果【获取具体的产品】 public function getResult(){ return $this->number_a + $this->number_b; }}//减法运算class CalculateSub extends Calculate{ //获取运算结果【获取具体的产品】 public function getResult(){ return $this->number_a - $this->number_b; }}//乘法 / 除法 等等其他运算【其他产品】
简单工厂模式
php
中,实现的方式其实就一个 switch
函数或者是 php8
新出的 match
函数来实例化所需要的产品生产类//根据运算不同实例化不同的对象//【也就是根据所需产品,实例化对应的产品类进行生产】//对应的实现其实就是一个switch或者php8函数新出的match函数//下面用最新的match函数做演示class CalculateFactory{ public static function setCalculate( $type = null ){ return match( $type ){ add => (function(){ return new CalculateAdd(); })(), sub => (function(){ return new CalculateSub(); })(), default => null; }; } }//具体使用$calculate = CalculateFactory::setCalculate(add);$calculate->setNumberA = 1;$calculate->setNumberB = 2;//计算echo $calculate->getResult;//echo 3
总结
:简单工厂模式其实就是创建一个基类【abstract
】,该类存放所有具体生产产品类的共用的代码
,但是没有执行过程
,然后具体生产产品的类全部继承基类再实现各自的生产过程
。最后创建一个工厂类,该类用来根据传入的参数
来获取所需的生产类
工厂方法模式
又称为工厂模式,属于创造型模式。在工厂模式中,工厂类的父类只负责定义公共接口,并不执行实际的生产动作。实际的生产动作则交给工厂的子类来完成。这样做将类的的实例化延迟到了工厂的子类,通过工厂的子类来完成实例化具体的产品,也就是生产interface CalculateFactory
】,可以是接口/抽象类
,这个抽象的工厂类可以派生出多个具体的工厂类【即FactoryAdd
以及FactorySub
】以下代码需要用到上面的生产抽象类:abstract class Calculate
以及具体的生产类,即:CalculateAdd
以及 CalculateSub
。下面不再重复实现
interface CalculateFactory{ public function CreateCalculate(); }class FactoryAdd implements CalculateFactory{ public function CreateCalculate(){ return new CalculateAdd(); } }class FactorySub implements CalculateFactory{ public function CreateCalculate(){ return new CalculateSub(); } }//具体使用//创建工厂实例$calculateFactory = new FactoryAdd();$add = $calculateFactory->CreateCalculate();$add->setNumberA( 1 );$add->setNumberB( 2 );//计算echo $add->getResult();//echo 3
只有一个工厂
来生产对应的生产对象【即CalculateFactory
】。而在工厂模式中,每一个生产产对象都由自己的工厂
来生产,并且这些工厂都继承
自同一个接口【即 interface CalculateFactory
】抽象工厂模式
抽象工厂模式提供创建一系列相关或相互依赖对象的接口,而且无需指定它们具体的类。这么理解很抽象。通俗一点的解释就是,相比于上面的工厂模式来讲,抽象工厂模式在每个不同的工厂之上又有一个超级工厂,这个超级工厂是抽象的接口【interface
】,用来生产具体的工厂abstract class Phone
以及abstract class Android
】,可以是接口/抽象类/普通类
,每个抽象产品类可以派生出多个具体产品类【即class IPhone
/ class MiPhone
以及 class IOS
/ class Android
】。一个抽象的工厂类【即interface AbstractFactory
】可以派生出多个具体的工厂类【即class iPhoneFactory
以及class MiFactory
】,且每个具体的工厂类可以创建多个产品类的实例【即都有createPhone
和createSystem
】//抽象的产品类abstract class Phone{}abstract class System{}//具体的产品类class IPhone extends Phone{}class MiPhone extends Phone{}//具体的产品类class IOS extends System{}class Android extends System{}//超级工厂interface AbstractFactory{ public function createPhone(); public function createSystem();}//具体的苹果工厂class iPhoneFactory implements AbstractFactory{ //生产苹果手机 public function createPhone(){ return new IPhone(); } //生产苹果系统 public function createSystem(){ return new IOS(); }}//具体的小米工厂class MiFactory implements AbstractFactory{ //生产小米手机 public function createPhone(){ return new MiPhone(); } //生产安卓系统 public function createSystem(){ return new Android(); }}
AbstarctFactory
】一个抽象产品类(可以是:接口,抽象类,普通类),可以派生出多个具体产品类
多带带一个具体的工厂类
每个具体工厂类只能创建一个具体产品类的实例
一个抽象产品类(可以是:接口,抽象类,普通类),可以派生出多个具体产品类
一个抽象工厂类(可以是:接口,抽象类),可以派生出多个具体工厂类
每个具体工厂类只能创建一个具体产品类的实例
多个抽象产品类(可以是:接口,抽象类,普通类),每个抽象产品类可以派生出多个具体产品类
一个抽象工厂类(可以是:接口,抽象类),可以派生出多个具体工厂类
每个具体工厂类可以创建多个具体产品类的实例
简单工厂模式只有一个抽象产品类,只有一个具体的工厂类
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个具体产品类的实例
Laravel-admin
进行举例先看下以下的代码,需求背景:需要根据角色不同显示不同的权限按钮
inRoles([AdminUserModel::getAssignmentRole()])) { $grid->disableBatchActions(); $grid->disableEditButton(); $grid->disableCreateButton(); $grid->disableDeleteButton(); } elseif (Admin::user()->inRoles([AdminUserModel::getEvaluatorRole()])) { $grid->disableBatchActions(); $grid->disableEditButton(); $grid->disableCreateButton(); $grid->disableDeleteButton(); $grid->actions(function (Grid/Displayers/Actions $actions) { $actions->append(new ConfirmCloseTaskAction()); }); } else { $grid->disableCreateButton(); $grid->disableDeleteButton(); $grid->disableEditButton(); $grid->disableBatchActions(); $grid->disableViewButton(); $grid->disableActions(); } }}
Controller
的增加】以及角色的增加,需要写更多重复的判断以及重复的代码抽象出一个产品类来派生出多个角色的权限产品类
抽象出一个工厂类来派生出多个具体的工厂类,这些工厂类表现为对应要使用权限按钮的场景
每个具体工厂【使用权限按钮的场景】可以创建多个具体产品类【即实例化多个角色的权限产品】
inRoles([$role]); } /** * 调用对应的方法 * [该方法其实就是工厂模式中的工厂,专门来生产的] * [多个工厂对应的就是各个需要用到Action权限的Controller控制器] * [每个Controller控制器来生产自己的Action权限] * [这个生产是通过反射来实现] * * @param Grid $grid * @param string $role * @param string $class * @throws /ReflectionException */ protected static function setRoleAction(Grid $grid, string $role, string $class) { $r = new /ReflectionClass($class); $methodName = $role . Action; if (!$r->hasMethod($methodName)) throw new /Exception(Method Not Found [ method : . $methodName . ] ); $method = $r->getMethod($methodName); $method->invoke($r->newInstance(), $grid); }}
showActions(); $grid->showViewButton(); } //在TaskController下有需要使用权限按钮的角色 //财务角色 public function financeAction(Grid $grid) { $grid->showActions(); $grid->showViewButton(); } //在TaskController下有需要使用权限按钮的角色 //业务员角色 public function salesmanAction(Grid $grid) { } //....其他角色}
TaskController
中控制权限的代码直接优化成如下:【优雅了不少~
】inRoles([AdminUserModel::getAssignmentRole()])) { $grid->disableBatchActions(); $grid->disableEditButton(); $grid->disableCreateButton(); $grid->disableDeleteButton(); } elseif (Admin::user()->inRoles([AdminUserModel::getEvaluatorRole()])) { $grid->disableBatchActions(); $grid->disableEditButton(); $grid->disableCreateButton(); $grid->disableDeleteButton(); $grid->actions(function (Grid/Displayers/Actions $actions) { $actions->append(new ConfirmCloseTaskAction()); }); } else { $grid->disableCreateButton(); $grid->disableDeleteButton(); $grid->disableEditButton(); $grid->disableBatchActions(); $grid->disableViewButton(); $grid->disableActions(); } */ }}
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/123756.html
摘要:工厂模式,依赖转移当然,实现控制反转的方法有几种。其实我们稍微改造一下这个类,你就明白,工厂类的真正意义和价值了。虽然如此,工厂模式依旧十分优秀,并且适用于绝大多数情况。 此篇文章转载自laravel-china,chongyi的文章https://laravel-china.org/top...原文地址: http://www.insp.top/learn-lar... ,转载务必保...
摘要:本文一大半内容都是通过举例来让读者去理解什么是控制反转和依赖注入,通过理解这些概念,来更加深入。这种由外部负责其依赖需求的行为,我们可以称其为控制反转。工厂模式,依赖转移当然,实现控制反转的方法有几种。 容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器,它存放的不是文本、数值,而是对象、对象的描...
摘要:使用元数据包中包含了中每一个被建模类对应的接口。任何对象的元数据是使用的实现来表示的。加载模型的序列化形式是个在运行期间获取元数据的有效方法。反射提供一个反射式,可以检查对象的元数据以及一般地访问和操纵数据。 使用元数据 Java包org.eclipse.emf.ecore中包含了Ecore中每一个被建模类对应的接口。任何EMF对象的元数据是使用Ecore的实现(implement...
摘要:提供了个常用的预定义接口,实现某些特定的能力。是啥如官方文档所述,它提供像访问数组一样访问对象的能力的接口。它提供了个接口我们实现这个接口,依次对应数组的读取,设置,操作。用上了它,可以让一个类即可以支持对象引用,也支持数组引用。 php提供了6个常用的预定义接口,实现某些特定的能力。其中最最常用的就是 ArrayAccess 了,像 Laravel 这种流行的框架都用到了它。 Arr...
近期在维护公司项目的时候遇到一个问题,因为实体类中的 set 方法涉及到了业务逻辑,因此在给对象赋值的过程中不能够使用 set 方法,为了实现功能,所以采用了反射的机制给对象属性赋值,借此机会也了解了反射的一些具体用法和使用场景,分以下两点对反射进行分析: 反射的优势和劣势 反射的应用场景 反射的优势和劣势 个人理解,反射机制实际上就是上帝模式,如果说方法的调用是 Java 正确的打开方式...
阅读 681·2023-04-25 19:43
阅读 3853·2021-11-30 14:52
阅读 3726·2021-11-30 14:52
阅读 3793·2021-11-29 11:00
阅读 3745·2021-11-29 11:00
阅读 3811·2021-11-29 11:00
阅读 3528·2021-11-29 11:00
阅读 6007·2021-11-29 11:00