Одним из основных принципов проектирования является программа для интерфейса, а не реализация. Возможно ли это в php или любом другом слабо типизированном языке.
РЕДАКТИРОВАТЬ:
Я, возможно, не написал вопрос так четко, как должен. Я не имею в виду, что php не может использовать интерфейсы – это может быть невозможно. Я имею в виду, что принцип дизайна «программа для интерфейса, а не реализация» становится излишним в слабо типизированных языках.
Да. Определите интерфейс:
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
Я не знаю, почему было бы невозможно иметь интерфейсы только потому, что язык слабо типизирован.
EDIT: точка (более или менее) имеет интерфейс, поэтому вы можете повторно использовать свой код независимо от класса, который фактически реализует указанный интерфейс.
Скажем, ваша программа использует интерфейс Set
, который имеет методы addItem()
, removeItem()
и contains()
. С интерфейсами вы знаете, что сможете вызвать любой из этих 3 методов независимо от базовой реализации Set
, будь то HashSet, TreeSet или что-то еще.
Это не изменится, если вы используете слабо типизированный язык; вы все равно можете использовать код, как если бы вы использовали строго типизированный язык. Я знаю, что я не очень хорошо объяснил это объяснение, но надеюсь, что вы поняли это.
php имеет интерфейсы, и вы можете запрограммировать их. Почему бы вам не сделать это?
Программирование на интерфейс означает, что вы просто используете функциональные возможности, предлагаемые интерфейсом, и не полагайтесь на детали реализации и не используете другие функции, предлагаемые реализацией, и вы просто знаете об этом, потому что реализация может измениться (интерфейс не должны).
Зависит от того, что вы подразумеваете под «интерфейсом» и «реализацией». Это свободные члены, значения которых могут меняться в зависимости от контекста.
PHP5 содержит конструкции ООП, подобные Java и C #, такие как объекты как ссылки, классы, абстрактные классы и интерфейсы. Он также содержит указания типа для параметров метода. Эти инструменты могут быть и использовались для создания «интерфейса» для чего-то.
Конечной целью является наличие интерфейса, на который соглашается каждый компонент.
Итак, если, например, я создавал сайт JavaScript, который был выполнен – в основном – в реализации старой MVC (не Rails / PHP), и полностью в AJAX, я бы удостоверился, что каждый из компонентов реализовал тот же интерфейс для наблюдения.
В каждой модели / представлении / контроллере я мог бы назвать мой метод «подписаться» совершенно другим. Или я мог бы реализовать стандартный интерфейс для каждого.
Поэтому у меня может быть общедоступный метод «.Register (event_type, subscriptioning_class)», реализованный в КАЖДОМ одном компоненте, который можно было бы назвать вызываемым.
Аналогично, у меня может быть общедоступный метод «.Update (event_type, data)», реализованный в КАЖДОМ одном компоненте, который можно было бы назвать вызываемым.
.Register и .Update – это интерфейс для моей связи с Observer. Внутри моих классов каждый может иметь метод «.Subscribe (издатель, 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 таким образом – они не являются частью общедоступного интерфейса. Они могут быть тем, что я хочу.
.Subscribe может взять ARRAY издателей и проталкивать ее через цикл, чтобы подписаться на несколько точек данных. Или возьмите массив из {"pub": x, "type": y} литералы объектов и вызовите метод .Register для каждого из них, чтобы вы могли полностью отключить загрузку этого класса с помощью одного вызова функции.
То же самое происходит с созданием приложения для аудио-плееров. Мне все равно, какие общие свойства MusicPlayer разделяют. Я знаю, что он использует .Play (), .Pause (), .Stop (), .Load (track).
Если я убеждаюсь, что я ТОЛЬКО использую согласованные методы открытого интерфейса, программа будет работать. Зачем?
Потому что парень, который работает на MusicPlayer, может изменить внутренности MusicPlayer. Он мог бы полностью переписать их. Возможно, есть метод ._ precacheSong (track). Но что, если его заменит. _cueTrack (трек) по дороге?
Вы просто используете виджет какого-то чувака, и однажды ваш виджет выйдет из строя, потому что вы расширяете его или реализуете его на основе не-интерфейсных методов или данных без интерфейса, которые произошли с изменением версии v1.2.1
Так что даже в Loose Languages интерфейс очень важен. Они дают вам карту того, как вы можете рассчитывать на вызов ЛЮБОГО компонента, который, как ожидается, будет иметь эту функциональность – и независимо от того, как работают внутренние компоненты этого компонента, входы и выходы будут одинаковыми (хотя больше проверки типов / ошибок требуется на входе).
Они позволяют вам «Duck-Type» очень легко (взять список разных экземпляров класса), сбрасывать один и тот же вызов функции на каждом из них, ожидая, что каждый из них имеет тот же метод и принимает тот же формат данных).
Еще лучше с JavaScript:
Мой код .Subscribe может даже быть написан только один раз, а затем привязан ко всему, что я хочу «наследовать».
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);
И я могу делать это свободно, потому что я знаю, что все, что я хочу подписаться, будет иметь тот же публичный интерфейс.