编程到接口而不是php中的实现

时间:2010-08-01 20:23:49

标签: php

主要设计原则之一是接口的程序而不是实现。这甚至可以在PHP或任何其他弱类型语言中使用。

编辑:

我可能没有像我应该的那样清楚地写出这个问题。我不是说php不能使用接口 - 它显然可以。我的意思是设计原则“接口而不是实现的程序”在弱类型语言中变得多余。

4 个答案:

答案 0 :(得分:4)

是。定义界面:

interface iTemplate
{
    public function setVariable($name, $var);
    public function getHtml($template);
}

并实施它:

// Implement the interface
class Template implements iTemplate
{
    private $vars = array();

    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }

    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
            $template = str_replace('{' . $name . '}', $value, $template);
        }

        return $template;
    }
}

接口上的PHP手册:http://php.net/manual/en/language.oop5.interfaces.php

我不知道为什么不能仅仅因为语言类型很弱而不能使用接口。


编辑:拥有一个接口的点(或多或少)是这样你可以重复使用你的代码而不管实际实现所述接口的类。

假设您的程序使用的接口Set,其中包含addItem()removeItem()contains()方法。使用接口,您知道无论基础Set实现如何,您都可以调用这3种方法中的任何一种,无论是HashSet,TreeSet还是其他任何方法。

如果您使用的是弱类型语言,则不会改变;你仍然可以像使用强类型语言一样进行编码。我知道我没有把这个解释说得很好,但我希望你能得到这个想法。

答案 1 :(得分:0)

php有interfaces,你可以编程给他们。你为什么不能这样做?

对接口进行编程意味着您只需使用接口提供的功能,既不依赖于实现细节也不使用实现提供的其他功能,您只是碰巧知道它,因为实现可能会改变(界面不应该)。

答案 2 :(得分:0)

取决于“界面”和“实施”的含义。这些是松散的术语,其含义可根据具体情况而变化。

PHP5包含类似于Java和C#的OOP结构,例如作为引用的对象,类,抽象类和接口。它还包含方法参数的类型提示。这些工具可以并且已经被用于构建某种东西的“界面”。

答案 3 :(得分:0)

最终目标是拥有一个每个组件都同意的界面。

所以,例如,如果我正在构建一个在旧式MVC(非Rails / PHP)实现中完成的JavaScript站点,并且完全在AJAX中,我会确保每个组件实现了相同的观察接口。

在每个模型/视图/控制器中,我可以将我的“订阅”方法命名为完全不同的东西。 或者,我可以为每个实现标准接口。

所以我可以在每个单独的组件中实现一个公共的“.Register(event_type,subscribing_class)”方法,这个方法可以被调用。

同样,我可以在每个单独的组件中实现一个公共的“.Update(event_type,data)”方法,这个方法可以被调用。

.Register和.Update是我的Observer通信的接口。 在我的类中,每个类都可能有一个“.Subscribe(publisher,event_type,self_reference)”方法。 该方法可能只是:

Class.Subscribe = function (publisher, event_type) {
    var self_reference = this;
    publisher.Register(event_type, self_reference);
};

每个人都可能有一个内部.Notify方法:

Class.Notify = function (type, data) {
    var subscribers = this.subscribers[type],
        i = 0, l = subscribers.length;

    for (; i < l; i++) { subscribers[i].Update(type, data); }
};

因为我同意我的所有通信界面都会以这种方式行事,所以我的内部结构看起来并不重要。

我的模型可能会继续忘记我的视图,我的视图可能会继续忘记我的控制器。

.Notify和.Subscribe不需要以这种方式实现 - 它们不是公共可访问界面的一部分。它们可能是我想要的任何东西。

。订阅可以使用ARRAY发布者并通过for循环推送,以订阅多个数据点。或者取一个{“pub”:x,“type”:y}对象文字的数组,然后调用每个对象文字的.Register方法,这样你就可以通过一个函数调用来完成该类的所有引导。

制作音频播放器应用也是如此。 我不关心MusicPlayer共享什么公共属性。 我知道它使用.Play(),. Use(),. Stop(),. Load(track)。

如果我确保我只使用商定的公共接口方法,该程序将会起作用。 为什么呢?

因为在MusicPlayer上工作的人可能会改变MusicPlayer的内部结构。 他可能会完全改写它们。也许有一个._ precacheSong(track)方法。 但是,如果它被替换为。 _cueTrack(track),那该怎么办?

你只是使用了一些家伙的小部件,有一天你的小部件崩溃了,因为你正在扩展或基于非接口方法或非接口数据实现它,这种情况在v1.2.1中发生了变化

所以即使在Loose Languages中,界面也很重要。 它们为您提供了如何预期调用任何预期具有该功能的组件的映射 - 无论该组件的内部如何工作,输入和输出都将完全相同(尽管更多类型/错误检查输入时需要。)

它们允许您非常轻松地“Duck-Type”(获取不同类实例的列表 - 在每个实例上触发相同的函数调用,期望每个具有相同的方法并采用相同的数据格式)。

使用JavaScript更好:

我的。订阅代码甚至可能只编写一次,然后绑定到我想“继承”它的任何内容。

Interface.Subscribe = function (publisher, evt_type) {
    var self_ref = this;
    publisher.Register(evt_type, self_ref);
};

Class_1.Subscribe = Interface.Subscribe.bind(Class_1);
Class_2.Subscribe = Interface.Subscribe.bind(Class_2);
Class_3.Subscribe = Some_Other_Interface.Subscribe.bind(Class_3);

我可以自由地做到这一点,因为我知道我想要订阅的所有东西都将拥有相同的公共界面。