Разные интерфейсы, одинаковые методы

Redjik, получилось, что WeightResolver должен знать ОГРОМНУЮ IEntity, хотя в пакете для WeightResolver разработчики не имеют понятия, что кроме веса будет ещё и цвет. IEntity существует только в моём проекте. WeightResolver и ColorResolver принадлежат различным проектам и также не имеют общих предков.

Это был бы замечательный вариант, если бы один разработчик мог контролировать всех и вся. Но зачастую можно контролировать только самую верхушку. Нельзя даже положиться на то, что в пространстве имён Vendor\Weight класс будет называться WeightResolver, а не просто Resolver, ибо такое уточняющее название сродни комментарию вида:
PHP:
n++ //увеличиваем n на единицу


флоппик,
попытки использования интерфейсов для указания различного поведения - противоречит смыслу и цели интерфейсов
В таком виде это утверждение просто не верно.

Например:
PHP:
SplDoublyLinkedList implements Iterator , ArrayAccess , Countable {
};

Каждый из объявленных контрактов указывает компилятору/интерпретатору определённый аспект поведения конкретной реализации, поведение различно. Нельзя использовать Countable там, где используется Iterator, однако можно одновременно быть и тем, и другим.

Я уже неоднократно писал, что IResolveCat и IResolveDog не полиморфны, потому проблемы ромбовидного наследования здесь нет.
 
Кто о чем, а вшивый о бане...
Redjik, получилось, что WeightResolver должен знать ОГРОМНУЮ IEntity, хотя в пакете для WeightResolver разработчики не имеют понятия, что кроме веса будет ещё и цвет. IEntity существует только в моём проекте. WeightResolver и ColorResolver принадлежат различным проектам и также не имеют общих предков.

1) С чего бы она была огромной - я твой монитор не вижу и мысли не читаю... по ходу пьесы у тебя появляются все новые условия, придумай еще чего-нить - не стесняйся.
2) Ты все время говоришь про РЕАЛИЗАЦИЮ, сколько можно то!!!111
3) Инерфейсы - АБСТРАКЦИЯ!!!111

Я не буду писать очередную портянку кода, хотя мой пример отлично модифицируется под твою задачу.
 
У меня вопрос (к ТС).
Расскажи, как ты собираешься реализовать метод resolve такой, что он удовлетворяет одновременно двум РАЗНЫМ интерфейсам.

Вообще, у тебя должно быть как-то так:

PHP:
class Cat implements IResolveCat { ... }
class Dog implements IResolveDog { ... }

class CatDog {

    public function __construct(Cat $cat, Dog $dog) {
         $this->cat = $cat;
         $this->dog = $dog;
    }

    public function getCat() {
        return $this->cat;
    }
    public function getDog() {
        return $this->dog;
    }

}
 
Не, вообще я понимаю ситуацию, когда два независимых пакета декларируют интерфейс с одинаковой сигнатурой и хочется в одном классе реализовать оба.
В той же java ситуация смягчается тем. что в сигнатуру входит не только имя, но и аргументы. В php не выйдет, придется бить по подклассам.
 
Но это одно устройство, которое не представляет ценности, если его разорвать.
Ну так, на радио приемнике для дураков есть надписи под ручками что в ООП мире будет выглядеть как-то так

PHP:
class RadioFacade implements IRadio
{
    public function setFrequency($level)
    {
        $this->getFrequencyModule()->set($level);
    }

    public function setPower($level)
    {
        $this->getPowerModule()->set($level);
    }
}

class FrequenyModule implements IFrequence
{
    protected $level;
   
    public function set($level)
    {
        $this->level = level;
    }
}

class PowerModule implements IPower
{
    protected $level;

    public function set($level)
    {
        $this->level = level;
    }
}
 
  • Like
Реакции: WMix
fixxxer,
Вообще, у тебя должно быть как-то так:
Один в один агрегатор интерфейсов. Мне уже предложенных на другом форуме. После пары итераций получилось:

PHP:
Interface IResolveDog {
    /**
    * @param Name
    * @return Dog
    */
    public function resolve(Name $name);
};

Interface IResolveCat {
    /**
    * @param Name
    * @return Cat
    */
    public function resolve(Name $name);
};

class CatDog {
    /* a lot of code goes here */

    /**
    * @return IResolveDog
    */
    public function asIResoveDog()
    {
        return new DogResolver($this);
    }

    /**
    * @return IResolveCat
    */
    public function asIResoveCat()
    {
        return new CatResolver($this);
    }
};

class DogResolver implements IResolveDog {
   public function __construct(CatDog $implementation)
   {
       /* construct Proxy */
   }

   /**
    * {@inheritdoc}
    */
    public function resolve(Name $name)
    {
        /* code for a dog goes here */
    }
};

Думаю, что такими декораторами можно решить более половины всех подобных случаев.

к ты собираешься реализовать метод resolve такой, что он удовлетворяет одновременно двум РАЗНЫМ интерфейсам

Если бы это был C++, то можно было расширить каждый из интерфейсов дополнительно и добавить по методу с другим названием, а потом оба унаследовать невиртуально и реализовать. Тогда в классе оказалось бы два разных метода с совершенно одинаковыми сигнатурами, но делающими совершенно разные вещи, потому что это были бы два совершенно разных метода.
В VC это можно сделать в точности, как в C#.


С C# ещё удобнее: просто два разных метода объявляются в классе и назначаются каждый на свой интерфейс.

Ясно, что разруливание такой ситуации, которая встречается чуть чаще, чем никогда не может быть простым. Но уровень удобства в цепочке PHP->Java->C++->C# понижается.
 
Последнее редактирование:
HraKK, пример хорош, да не тот. Объект же является усилителем. А для тех, кто является клиентами усилителя метод setPower не известен, известен метод set. Так что fixxer даёт более подходящий пример. Но его нужно адаптировать к ситуации, когда у котопса есть общие внутренности, состояние которых должно быть синхронизировано между вызовами на разных интерфейсах.

флоппик,
.
Определиться с чем?
Эти интерфейсы не полиморфны? -- Да. Эти интерфейсы делают что-то разное? -- Да. У них есть методы с одинаковой сигнатурой? -- Да.
 
Определиться с чем?
Эти интерфейсы не полиморфны? -- Да. Эти интерфейсы делают что-то разное? -- Да. У них есть методы с одинаковой сигнатурой? -- Да.
Определится, что эти неполиморфные разные интерфейсы с одинаковыми сигнатурами в принципе могут логически делать на одном и том же объекте.
 
Вот так бы это выглядело на C++:

Код:
namespace vendor {
  
struct IResolveCat {
    virtual void resolve() =0;
  
    virtual ~IResolveCat()
    {
    }
};

struct IResolveDog {
    virtual void resolve() =0;
      
    virtual ~IResolveDog()
    {
    }
};

void functionRequiresIResolveCat(vendor::IResolveCat& resolver)
{
    resolver.resolve();
}

void functionRequiresIResolveDog(vendor::IResolveDog& resolver)
{
    resolver.resolve();
}

} // namespace vendor

namespace my_namespace {
  
struct IResolveCat: public vendor::IResolveCat {
    virtual void resolve()
    {
        resolveCat();
    }
  
    virtual void resolveCat() =0;
  
    virtual ~IResolveCat()
    {
    }
};

struct IResolveDog: public vendor::IResolveDog {
    virtual void resolveDog() =0;
  
    virtual void resolve()
    {
        resolveDog();
    }
  
    virtual ~IResolveDog()
    {
    }
};
  
  
class Resolver: public virtual IResolveCat, public virtual IResolveDog {
    public:
        virtual void resolveCat();
        virtual void resolveDog();
};

void Resolver::resolveCat()
{
    std::cout << "I'm a CAT resolved by Resolver" << std::endl;
}
      
void Resolver::resolveDog()
{
    std::cout << "I'm a DOG resolved by Resolver" << std::endl;
}

} //namespace my_namespace

Никаких лишних вызовов при использовании, только неявное приведение типов.
 
флоппик, один интерфейс возвращает вес, другой цвет. Например.

Или открывать и закрывать двери:

PHP:
interface IOpenable {
    public function action();
};

interface ICloseable {
    public function action();
};

class Door implements IOpenable, ICloseable {
};
 
В каком, бл###, контексте тебе понадобится IOpenable? И почему метод называется «action», а не «close»? Абсолютно мусорный код. Где real life sample?
 
Кстати, да, а нахрена вообще одинаковые методы?
Ну вот нужен цвет и вес, ну пускай будет два интерфейса IWeightable, IColorable с методами getWeight() и getColor(), если не хочешь "светить" весь апи - отдаешь только один интерфейс.
Те, кто будут поддерживать твой код или будут писать на основе твоего апи - только спасибо скажут.

Если же ты наконец определишься с тем, что хочешь ... и сделаешь эту магическую фигню, которая не пойми как работает и возвращает рандомные результаты для одного и того же метода... - я бы даже браться не стал, если бы мне предложили с этим работать.
 
В той или иной мере сделать можно все, что угодно, только вот это не очень хорошая практика. И
Вот так бы это выглядело на C++:
.... эм, окей, хорошо, что я почти не пишу на C++, раз там могут наворотить такое для простенькой задачки
 
да хрена два, на плюсах ты описал совершенно другое. у тебя нет одного и тогоже метода от двух разных интерфейсов в одном классе, ты конкретно спрашиваешь у
Resolver тот или иной метод.
 
WMix, прочитайте внимательно первое сообщение в теме. В С++ примере делается именно то, что должно быть.
 
В C++ есть перегрузка и множественное наследование. С другой стороны в php у тебя нет статической типизации и есть трейты.
Покажи реальный пример, а не котопса и давай посмотрим, как это можно сделать красиво.
 
пространство имен в PHP есть. "пространство имен методов" в плюсах я не слышал (он и так в капсуле класса)
вне зависимости, если требуется чтоб в классе Resolver метод resolveCat() возвращал другое нежеле resolveDog(), то это и так происходит. Не понимаю зачем тебе interfaces или что ты там еще себе представляешь
class RadioFacade implements IRadio
делает тоже самое!
 
Сверху