文档章节

如何不使用继承来扩展一个类

汤汤圆圆
 汤汤圆圆
发布于 2015/12/23 21:54
字数 407
阅读 74
收藏 3
点赞 0
评论 0

允许多个类将方法添加到另外一个(相当于总控);我们可以在扩展类中使用魔术方法 __call()

class Foo
{
    public $dispatcher;
    public function __construct(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }

    public function __call($method, $arguments)
    {
        // 创建一个名称为 'foo.method_is_not_found'的事件
        $event = new HandleUndefinedMethodEvent($this, $method, $arguments);
        $this->dispatcher->dispatch('foo.method_is_not_found', $event);

        // 如果没有监听者处理该事件证明该方法不存在
        if (!$event->isProcessed()) {
            throw new \Exception(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
        }

        // 返回监听者设置的返回值
        return $event->getReturnValue();
    }
}

创建事件对象类

use Symfony\Component\EventDispatcher\Event;

class HandleUndefinedMethodEvent extends Event
{
    protected $subject;
    protected $method;
    protected $arguments;
    protected $returnValue;
    protected $isProcessed = false;

    public function __construct($subject, $method, $arguments)
    {
        $this->subject = $subject;
        $this->method = $method;
        $this->arguments = $arguments;
    }

    public function getSubject()
    {
        return $this->subject;
    }

    public function getMethod()
    {
        return $this->method;
    }

    public function getArguments()
    {
        return $this->arguments;
    }

    /**
     * 如果方法已经找到;设置返回值;且停止事件传播给其它监听者
     */
    public function setReturnValue($val)
    {
        $this->returnValue = $val;
        $this->isProcessed = true; //标识为已处理;证明方法存在;
        $this->stopPropagation(); //停止事件传播;
    }

    public function getReturnValue()
    {
        return $this->returnValue;
    }

    public function isProcessed()
    {
        return $this->isProcessed;
    }
}

添加监听者类

class Bar
{
    public function onFooMethodIsNotFound(HandleUndefinedMethodEvent $event)
    {
        // 仅仅调用bar方法的时候该监听者才处理;
        if ('bar' != $event->getMethod()) {
            //让其他的监听者处理未知的方法
            return;
        }

        //主题对像(foo 实例)
        $foo = $event->getSubject();

        // 获取bar方法参数
        $arguments = $event->getArguments();

        // ... do something

        // 设置返回值
        $event->setReturnValue("aaaaaa");
    }

}
    public function testNotMethodEventAction()
    {
        $bar = new Bar();
        $dispatcher = new EventDispatcher();
        $dispatcher->addListener("foo.method_is_not_found", array($bar, 'onFooMethodIsNotFound'));
        $foo = new Foo($dispatcher);
        $foo->bar();
        $foo->xxx();
        return new Response("xxxxaazzz");
    }

这个例子其实是通过foo通过事件(不是使用继承)来调用bar和其他监听中的某些方法

© 著作权归作者所有

共有 人打赏支持
汤汤圆圆

汤汤圆圆

粉丝 11
博文 63
码字总数 18884
作品 0
昌平
程序员
Objective-C,如何在不使用类继承的情况下,扩展已有类的实现

在Objective-C 2.0中,有2种办法可以在不使用类继承的情况下,扩展已有类的实现。一种是分类(Category),另一种是类扩展(Class Extensions)。 前者可以在没有已有类的源代码的情况下扩展类的...

nswish ⋅ 2014/08/13 ⋅ 0

OOAD理论知识小结

软件工程基本概念 软件工程三要素: 方法:完成软件开发的各项任务的技术方法,为软件开发提供 “如何做” 的技术 工具:为运用方法而提供的自动的或半自动的软件工程的支撑环境 过程:为了获...

陈嘻嘻哈哈 ⋅ 2015/07/23 ⋅ 0

Java中如何恰当的表达“继承”与“扩展”的语义?

”继承“是Java的面向对象学习过程中的大难题,原因有二: ”is-A“的关系本身就不好理解 Java中的extends“扩展”与面向对象中的“继承”inheritance不是一一对应的。 很多书里认为继承与扩...

monkeysayhi ⋅ 2017/10/30 ⋅ 0

Visual Studio 11开发指南(14)C++11---C++/ CX设计

Visual Studio 11引入了一些深入的新的语言扩展,官方称为C + + / CX,这为了支持新的 API 模型在 Windows 8 中。一般人都会熟悉 C + + / CLI (即我们提供针对 CLR 的语言扩展),语法不应该...

junwong ⋅ 2012/03/09 ⋅ 0

javascript 类的基础知识

经典的JavaScript构造 首先,让我们创建一个带有原型的简单构造函数。这是最接近你会在本地JavaScript找到一个类。这是非常强大的,高效的,但并没有完全工作就像你所期望的,如果从类的语言...

飞儿飞 ⋅ 2016/11/16 ⋅ 0

.Net的3C: CTS, CLS, CLR

【IT168 技术文档】.NET结合了Java和COM两者优点来解决互操作性问题。类似于COM定义的标准二进制格式,.NET定义了一个称为通用类型系统(Common Type System)的类型标准。这个类型系统不但实...

IT168网站 ⋅ 2009/05/27 ⋅ 0

初涉Android设计原则,设计模式

程序中所有的依赖关系都终止于抽象类或者接口, 才是真正的面向对象设计 设计原则一 : 单一职责原则 定义: 对于一个类,应该只有一个引起它变化的原因. 优点: 降低类的复杂度,提高类的可读性,...

小强强强 ⋅ 2015/01/26 ⋅ 0

Kotlin类和对象(四)——扩展和data类

扩展 与C#和Gosu类似,Kotlin提供既不使用继承也不使用任何类型的设计模式(如装饰者模式)扩展新功能类的能力。这种通过特殊声明的操作叫做扩展。Kotlin支持函数扩展和属性扩展。 扩展函数 ...

flueky ⋅ 2017/10/23 ⋅ 0

设计模式--设计原则

开闭原则 定义 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。模块应该尽量在不修改原代码的情况下进行扩展 注意事项   1.通过接口或者抽象类约束扩展,对扩展进行边界限定,不...

宿小帅 ⋅ 03/01 ⋅ 0

[译] 函数式 Mixin(软件编写)(第七部分)

原文地址:Functional Mixins 原文作者:本文已获原作者 Eric Elliott 授权 译文出自:掘金翻译计划 译者:yoyoyohamapi 校对者:Tina92 reid3290 Smoke Art Cubes to Smoke — MattysFli...

吴晓军 ⋅ 2017/06/21 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring表达式语言(SpEL)

1、SpEL引用 Spring EL在bean创建时执行其中的表达式。此外,所有的Spring表达式都可以通过XML或注解的方式实现。下面将使用Spring表达式语言(SpEL),注入字符串,整数,Bean到属性。 SpEL的...

霍淇滨 ⋅ 15分钟前 ⋅ 0

Gradle使用阿里云镜像

gradle 生命周期中有一个初始化( Initialization )的过程,这个过程运行在 build script 之前,我们可以在这个地方做一点系统全局的设置,如配置仓库地址。 你可以在以下几个位置实现仓库地址...

明MikeWoo ⋅ 23分钟前 ⋅ 0

appium+python3.6

1.安装jdk1.8(不知道为啥只识别1.8,1.10不识别,所以为了少折腾,迁就安装1.8) http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 配置 JAVA_HOME:...

Kampfer ⋅ 42分钟前 ⋅ 0

详解Apache 日志分割教程

一、日志切割 安装cronolog CentOS 5.3中编译安装Apache日志默认是不切割的,需要用用工具Cronnolog进行日志切割。 1.下载及安装 wget http://cronolog.org/download/cronolog-1.6.2.tar.gz ...

dragon_tech ⋅ 44分钟前 ⋅ 0

Keepalived介绍

负载均衡器(Load Balancer, LB )是一组能够将IP数据流以负载均衡形式转发到多台物理服务器的集成软件。有硬件负载均衡器和软件负载均衡器之分,硬件负载均衡器主要是在访问网络和服务器之间...

寰宇01 ⋅ 44分钟前 ⋅ 0

java8-Collections and Streams

stream和集合的区别是什么? 1.在计算的时候处理不同, 2.every element should be computed in the memory and then to be part of collections stream Stream apis filter with a predica......

writeademo ⋅ 50分钟前 ⋅ 0

Confluence 6 重新获得附件指南

每一个文件在恢复上传到 Confluence 的时候必须单独重命名,你可以通过下面说明的 3 个方法中选择一个进行操作: 选择 A - 通过文件名恢复附件 如果你知道你需要恢复的每一个文件名,尤其是你...

honeymose ⋅ 今天 ⋅ 0

【每天一个JQuery特效】根据状态确定是否滑入或滑出被选元素

主要效果: 本文主要采用slideToggle()方法实现以一行代码同时实现以展开或收缩的方式显示或隐藏被选元素。 主要代码如下: <!DOCTYPE html><html><head><meta charset="UTF-8">...

Rhymo-Wu ⋅ 今天 ⋅ 0

度量.net framework 迁移到.net core的工作量

把现有的.net framework程序迁移到.net core上,是一个非常复杂的工作,特别是一些API在两个平台上还不能同时支持。两个类库的差异性,通过人工很难识别全。好在微软的工程师们考虑到了我们顾...

李朝强 ⋅ 今天 ⋅ 0

请不要在“微服务”的狂热中迷失自我!

微服务在过去几年一直是一个非常热门的话题(附录1)。何为“微服务的疯狂”,举个例子: 众所周知,Netflix在DevOps上的表现非常棒。Netfix可以做微服务。因此:如果我做微服务,我也将非常...

harries ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部