в чем разница между
есть прикольная библиотека, там все функции которые нужны, еще 5 ненужных и одной не хватает, взял унаследовал, нехватающую дописал, лишнее не учел в интерфейсе,
// прикольная библиотека
class A{
public function b(){} // (одна) ненужных
// все функции которые нужны
public function c(){}
public function d(){}
}
interface D{
public function c();
public function d();
public function x();// и одной не хватает,
}
// решение наследованием
class B extends A implements D{
public function x(){
return $this->a($this->b()) +$this->c();
}
}
// решение композицией
class B implements D{
// вода или шум, хорошо что без комментов, иначе строк 70 ненужного кода
private $a;
public function __construct(A $a){
$this->a = $a;
}
public function c(){
return $this->a->c();
}
public function d(){
return $this->a->d();
}
// код
public function x(){
return $this->a($this->b()) +$this->c();
}
}
нужна конкретика, класс B можно легко заменитьИ вышел-таки снова на Дерибасовскую
class ThirdPartyLibrary {
public function foo(A $a) {..};
}
class MyLibrary {
public function bar(D $d) {..}
}
$d = new B(); // необязательно напрямую, пусть внутри DI, это ничего не меняет
$thirdPartyLibrary->foo($d);
$myLibrary->bar($d);
И вот уже не так-то легко.класс B можно легко заменить
наверняка есть. уже давно пора реализовать.в PhpStorm... ну, надо сделать фичреквест.
поменяйтебя не устраивает контракт метода c() и ты хочешь его поменять
не мешает2) ты обновил библиотеку и в новой версии появился метод x()
Даже говоря про ПХП, когда это было удобно для какого-то общего бойлерплейт кода, но сейчас есть хотя бы трейты.Наследование ок, когда наследуешься от абстрактного класса, при этом ничего не добавляешь к фактическому публичному интерфейсу класса, а только реализуешь абстрактные методы.
Во всех остальных случаях так или иначе возникнет проблема с LSP и/или DIP.
поменяй
1) LSPне мешает
Чувак, изучи наконец SOLID, сколько раз уже LSP упоминали — ты до сих пор не понимаешь этого.поменяй
фаталити2) Оказалось, что в приватном методе базового класса из библиотеки вызывается $this->c() и $this->x().
Я, кстати, считаю трейты (в таком виде, в каком они реализованы в PHP) ошибкой дизайна. Было бы намного лучше, если бы реализовали Java 8 default methods в интерфейсах (кажется, все разумные случаи использования трейтов сводятся к некоей дефолтной реализации определенного интерфейса).Даже говоря про ПХП, когда это было удобно для какого-то общего бойлерплейт кода, но сейчас есть хотя бы трейты.
import java.time.*;
public interface TimeClient {
void setTime(int hour, int minute, int second);
void setDate(int day, int month, int year);
void setDateAndTime(int day, int month, int year,
int hour, int minute, int second);
LocalDateTime getLocalDateTime();
static ZoneId getZoneId (String zoneString) {
try {
return ZoneId.of(zoneString);
} catch (DateTimeException e) {
System.err.println("Invalid time zone: " + zoneString +
"; using default time zone instead.");
return ZoneId.systemDefault();
}
}
default ZonedDateTime getZonedDateTime(String zoneString) {
return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
}
}
Легко, если рассматривать какие-нибудь базово-инфраструктурные штуки типа Collection и их "расширения" типа Countable/Iterable, которые хочется уметь комбинировать произвольно.Мне кажется будет крайне сложно найти такой пример где нужен будет именно интерфейс с дефолт методами(вместо абстрактного класса). Эта всеобщая любовь к интерфейсам(относительно абстрактных классов) немного туманит рассуждения.