企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
# 多态 ## **多态** 多态是指在面向对象中能够根据使用类的上下文来重新定义或改变类的性质和行为 一个对外接口,多个内部实现方法 多态性的一般定义为:**同一个操作作用于不同的类的实例,将产生不同的执行结果**。即不同类的对象收到相同的消息时,将得到不同的结果。 在实际的应用开发中,采用面向对象中的多态主要在于可以**将不同的子类对象都当作一个父类来处理**,并且可以屏蔽不同子类对象之间所存在的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化 如例子2: 具有表现多种形态的能力特征。在面向对象中表示根据对象的类型以不同方式处理。多态性允许每个对象以适合自身的方式去响应共同的消息。多态性增强了软件的灵活性和重用性。 > 多态一般用接口做最好 ``` <pre class="calibre10">``` <span class="token1"><</span><span class="token1">?</span>php <span class="token">// 多态:多种形态</span> <span class="token">// 走路</span> <span class="token">// 坐公交</span> <span class="token">// 骑自行车</span> abstract class <span class="token4">Style</span> <span class="token3">{</span> <span class="token">// 上</span> abstract public <span class="token5">function</span> <span class="token4">up</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">// 下</span> abstract public <span class="token5">function</span> <span class="token4">down</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">// 走路的方式(继承了Style,就必须实现up和down两个方法)</span> class <span class="token4">Walk</span> extends <span class="token4">Style</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">up</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">'迈左腿走路<br>'</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">down</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">'迈右腿走路<br>'</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">// 坐公交的方式</span> class <span class="token4">Bus</span> extends <span class="token4">Style</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">up</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">'上车<br>'</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">down</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">'下车<br>'</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">// 自行车</span> class <span class="token4">Bike</span> extends <span class="token4">Style</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">up</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">'左腿蹬车<br>'</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">down</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">'右腿等车<br>'</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> ``` ``` 获取来学校的方式(Style作为类型约束条件,约束必须传递的参数是其子类实例化的对象) ``` <pre class="calibre10">``` <span class="token5">function</span> <span class="token4">getStyle</span><span class="token3">(</span>Style $obj<span class="token3">)</span> <span class="token3">{</span> <span class="token">/* if ($obj instanceof Walk) { $obj->leftTui(); $obj->rightTui(); } else if ($obj instanceof Bus) { $obj->up(); $obj->down(); } else if ($obj instanceof Bike) { $obj->leftDeng(); $obj->rightDeng(); }*/</span> $obj<span class="token1">-</span><span class="token1">></span><span class="token4">up</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $obj<span class="token1">-</span><span class="token1">></span><span class="token4">down</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> $w <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Walk</span><span class="token3">;</span> $b <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Bus</span><span class="token3">;</span> $bike <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Bike</span><span class="token3">;</span> <span class="token4">getStyle</span><span class="token3">(</span>$w<span class="token3">)</span><span class="token3">;</span> <span class="token4">getStyle</span><span class="token3">(</span>$b<span class="token3">)</span><span class="token3">;</span> <span class="token4">getStyle</span><span class="token3">(</span>$bike<span class="token3">)</span><span class="token3">;</span> ``` ``` 获取来学校的方式(Style作为类型约束条件,约束必须传递的参数是其子类实例化的对象) ``` <pre class="calibre10">``` <span class="token5">function</span> <span class="token4">getStyle</span><span class="token3">(</span>Style $obj<span class="token3">)</span> <span class="token3">{</span> $obj<span class="token1">-</span><span class="token1">></span><span class="token4">up</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $obj<span class="token1">-</span><span class="token1">></span><span class="token4">down</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> $w <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Walk</span><span class="token3">;</span> $b <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Bus</span><span class="token3">;</span> $bike <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Bike</span><span class="token3">;</span> <span class="token4">getStyle</span><span class="token3">(</span>$w<span class="token3">)</span><span class="token3">;</span> <span class="token4">getStyle</span><span class="token3">(</span>$b<span class="token3">)</span><span class="token3">;</span> <span class="token4">getStyle</span><span class="token3">(</span>$bike<span class="token3">)</span><span class="token3">;</span> ``` ``` 例子2:多态的应用设计 > 在实际的应用开发中,通常为了使项目能够在以后的时间里的轻松实现扩展与升级,需要通过继承实现可复用模块进行轻松升级。在进行可复用模块设计时,就需要尽可能的减少使用流程控制语句。此时就可以采用多态实现该类设计。 通常采用流程控制语句实现不同类的处理。其代码如下所示。 ``` <pre class="calibre10">``` class <span class="token4">painter</span><span class="token3">{</span> <span class="token">//定义油漆工类</span> public <span class="token5">function</span> <span class="token4">paintbrush</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//定义油漆工动作</span> echo <span class="token2">"油漆工正在刷漆!/n"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">typist</span><span class="token3">{</span> <span class="token">//定义打字员类</span> public <span class="token5">function</span> <span class="token4">typed</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//定义打字员工作</span> echo <span class="token2">"打字员正在打字!/n"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token5">function</span> <span class="token4">printworking</span><span class="token3">(</span>$obj<span class="token3">)</span><span class="token3">{</span> <span class="token">//定义处理类的函数</span> <span class="token5">if</span><span class="token3">(</span>$obj <span class="token5">instanceof</span> <span class="token4">painter</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//若对象是油漆工类,则显示油漆工动作</span> $obj<span class="token1">-</span><span class="token1">></span><span class="token4">paintbrush</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span><span class="token4">elseif</span><span class="token3">(</span>$obj <span class="token5">instanceof</span> <span class="token4">typist</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//若对象是打字员类,则显示打字员动作</span> $obj<span class="token1">-</span><span class="token1">></span><span class="token4">typed</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span><span class="token5">else</span><span class="token3">{</span> <span class="token">//若非以上类,则显示出错信息</span> echo <span class="token2">"Error: 对象错误!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token4">printworking</span><span class="token3">(</span><span class="token5">new</span> <span class="token4">painter</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//显示员工工作</span> <span class="token4">printworking</span><span class="token3">(</span><span class="token5">new</span> <span class="token4">typist</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//显示员工工作</span> ``` ``` 分析:在上述程序中,首先定义两个员工类:油漆工类和打字员类。然后定义一个处理函数,在该函数中,判断员工是否为已经定义的员工,打印出员工的工作状态。其结果如下所示。 油漆工正在刷漆 打字员正在打字 从 以上程序可轻松看出,若想显示其几种员工的工作状态,需要首先定义该员工类,并在该员工类中定义员工的工作,然后在printworking()函数中增 加elseif语句以检查对象是哪一员工类的实例。这在实际的应用中,是非常不可取的。若此时采用多态,则可以轻松解决此问题。 可以首先创建一个员工父类,所有的员工类将继承自该员工父类,并且继承父类的所有方法与属性。然后在员工类中创建“是一”关系,判断是否为合法的员工。 【示例】例举了采用多态的方式改写上例。其代码如下所示。 \*/ //代码如下: ``` <pre class="calibre10">``` class <span class="token4">employee</span><span class="token3">{</span><span class="token">//定义员工父类</span> protected <span class="token5">function</span> <span class="token4">working</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span><span class="token">//定义员工工作,需要在子类的实现</span> echo <span class="token2">"本方法需要在子类中重载!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">painter</span> extends <span class="token4">employee</span><span class="token3">{</span><span class="token">//定义油漆工类</span> public <span class="token5">function</span> <span class="token4">working</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span><span class="token">//实现继承的工作方法</span> echo <span class="token2">"油漆工正在刷漆!/n"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">typist</span> extends <span class="token4">employee</span><span class="token3">{</span><span class="token">//定义打字员类</span> public <span class="token5">function</span> <span class="token4">working</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> echo <span class="token2">"打字员正在打字!/n"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">manager</span> extends <span class="token4">employee</span><span class="token3">{</span><span class="token">//定义经理类</span> public <span class="token5">function</span> <span class="token4">working</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> echo <span class="token2">"经理正在开会!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token5">function</span> <span class="token4">printworking</span><span class="token3">(</span>$obj<span class="token3">)</span><span class="token3">{</span><span class="token">//定义处理方法</span> <span class="token5">if</span><span class="token3">(</span>$obj <span class="token5">instanceof</span> <span class="token4">employee</span><span class="token3">)</span><span class="token3">{</span><span class="token">//若是员工对象,则显示其工作状态</span> $obj<span class="token1">-</span><span class="token1">></span><span class="token4">working</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span><span class="token5">else</span><span class="token3">{</span><span class="token">//否则显示错误信息</span> echo <span class="token2">"Error: 对象错误!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token4">printworking</span><span class="token3">(</span><span class="token5">new</span> <span class="token4">painter</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span><span class="token">//显示油漆工的工作</span> <span class="token4">printworking</span><span class="token3">(</span><span class="token5">new</span> <span class="token4">typist</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span><span class="token">//显示打字员的工作</span> <span class="token4">printworking</span><span class="token3">(</span><span class="token5">new</span> <span class="token4">manager</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span><span class="token">//显示经理的工作</span> ``` ``` 分析:在上述程序中,首先定义一个员工基类,并定义一个员工工作状态的方法。然后定义将继承自员工基类的三个员工类:油漆工类、打字员类和经理类。然后定义显示员工工作状态的方法。并在该方法中创建一个“是一”关系,用于判断是否为合法的员工。其结果如下所示。 油漆工正在刷漆! 打字员正在打字! 经理正在开会! 从上例可发现,无论增加多少个员工类,只需要实现自员工父类继承的该员工类和方法。而无须修改显示员工工作状态的方法printworking()。 还有一只是改变参数数量的重载,同样是因为PHP也不支持方法的重载,所以也需要些变通的方法实现,如下: ``` <pre class="calibre10">``` <span class="token">// 通过可变参数来达到改变参数数量重载的目的</span> <span class="token">// 不是必须传入的参数,必须在函数定义时赋初始值</span> <span class="token5">function</span> <span class="token4">open_database</span><span class="token3">(</span>$DB<span class="token3">,</span> $cache_size_or_values<span class="token1">=</span><span class="token5">null</span><span class="token3">,</span> $cache_size<span class="token1">=</span><span class="token5">null</span><span class="token3">)</span> <span class="token3">{</span> switch <span class="token3">(</span><span class="token4">function_num_args</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span> <span class="token">// 通过function_num_args()函数计算传入参数的个数,根据个数来判断接下来的操作</span> <span class="token3">{</span> case <span class="token6">1</span><span class="token3">:</span> $r <span class="token1">=</span> <span class="token4">select_db</span><span class="token3">(</span>$DB<span class="token3">)</span><span class="token3">;</span> <span class="token5">break</span><span class="token3">;</span> case <span class="token6">2</span><span class="token3">:</span> $r <span class="token1">=</span> <span class="token4">select_db</span><span class="token3">(</span>$DB<span class="token3">,</span> $cache_size_or_values<span class="token3">)</span><span class="token3">;</span> <span class="token5">break</span><span class="token3">;</span> case <span class="token6">3</span><span class="token3">:</span> $r <span class="token1">=</span> <span class="token4">select_db</span><span class="token3">(</span>$DB<span class="token3">,</span> $cache_size_or_values<span class="token3">,</span> $cache_size<span class="token3">)</span><span class="token3">;</span> <span class="token5">break</span><span class="token3">;</span> <span class="token3">}</span> <span class="token5">return</span> <span class="token4">is_resource</span><span class="token3">(</span>$r<span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> ``` ``` 例子4: ``` <pre class="calibre17">``` <span class="token1"><</span><span class="token1">?</span>php <span class="token">/** * 虚基类 */</span> abstract class <span class="token4">T</span><span class="token3">{</span> abstract <span class="token5">function</span> <span class="token4">show</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">/** * 子类 */</span> class <span class="token4">T1</span> extends <span class="token4">T</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">show</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> echo <span class="token2">"T1 from abstract class!<br/>"</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">show1</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> echo <span class="token2">"T1 not from abstract class!<br/>"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">/** * 子类 */</span> class <span class="token4">T2</span> extends <span class="token4">T</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">show</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> echo <span class="token2">"T2 from abstract class!<br/>"</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">show1</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> echo <span class="token2">"T2 not from abstract class!<br/>"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">T3</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">show</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> echo <span class="token2">"in T3!<br/>"</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">show1</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> echo <span class="token2">"in T3!<br/>"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> $t1 <span class="token1">=</span> <span class="token5">new</span> <span class="token4">T1</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $t2 <span class="token1">=</span> <span class="token5">new</span> <span class="token4">T2</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $t3 <span class="token1">=</span> <span class="token5">new</span> <span class="token4">T3</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token4">show</span><span class="token3">(</span>$t1<span class="token3">)</span><span class="token3">;</span> <span class="token4">show</span><span class="token3">(</span>$t2<span class="token3">)</span><span class="token3">;</span> <span class="token">//报错,$t3不是T,所以被show函数调用的时候,会报类型不对的错误</span> <span class="token">//show($t3);</span> <span class="token5">function</span> <span class="token4">show</span><span class="token3">(</span> T $t <span class="token3">)</span><span class="token3">{</span><span class="token">//注意参数的类型</span> $t<span class="token1">-</span><span class="token1">></span><span class="token4">show</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $t<span class="token1">-</span><span class="token1">></span><span class="token4">show1</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> ``` ```