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

Lionishy

Новичок
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

Джедай-мастер
Кто о чем, а вшивый о бане...
Redjik, получилось, что WeightResolver должен знать ОГРОМНУЮ IEntity, хотя в пакете для WeightResolver разработчики не имеют понятия, что кроме веса будет ещё и цвет. IEntity существует только в моём проекте. WeightResolver и ColorResolver принадлежат различным проектам и также не имеют общих предков.
1) С чего бы она была огромной - я твой монитор не вижу и мысли не читаю... по ходу пьесы у тебя появляются все новые условия, придумай еще чего-нить - не стесняйся.
2) Ты все время говоришь про РЕАЛИЗАЦИЮ, сколько можно то!!!111
3) Инерфейсы - АБСТРАКЦИЯ!!!111

Я не буду писать очередную портянку кода, хотя мой пример отлично модифицируется под твою задачу.
 

fixxxer

К.О.
Партнер клуба
У меня вопрос (к ТС).
Расскажи, как ты собираешься реализовать метод 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;
    }

}
 

fixxxer

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

флоппик

promotor fidei
Команда форума
Партнер клуба

HraKK

Мудак
Команда форума
Но это одно устройство, которое не представляет ценности, если его разорвать.
Ну так, на радио приемнике для дураков есть надписи под ручками что в ООП мире будет выглядеть как-то так

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

Lionishy

Новичок
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# понижается.
 
Последнее редактирование:

Lionishy

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

флоппик,
.
Определиться с чем?
Эти интерфейсы не полиморфны? -- Да. Эти интерфейсы делают что-то разное? -- Да. У них есть методы с одинаковой сигнатурой? -- Да.
 

флоппик

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

Lionishy

Новичок
Вот так бы это выглядело на 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
Никаких лишних вызовов при использовании, только неявное приведение типов.
 

Lionishy

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

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

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

interface ICloseable {
    public function action();
};

class Door implements IOpenable, ICloseable {
};
 

Вурдалак

Продвинутый новичок
В каком, бл###, контексте тебе понадобится IOpenable? И почему метод называется «action», а не «close»? Абсолютно мусорный код. Где real life sample?
 

Redjik

Джедай-мастер
Кстати, да, а нахрена вообще одинаковые методы?
Ну вот нужен цвет и вес, ну пускай будет два интерфейса IWeightable, IColorable с методами getWeight() и getColor(), если не хочешь "светить" весь апи - отдаешь только один интерфейс.
Те, кто будут поддерживать твой код или будут писать на основе твоего апи - только спасибо скажут.

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

Redjik

Джедай-мастер
В той или иной мере сделать можно все, что угодно, только вот это не очень хорошая практика. И
Вот так бы это выглядело на C++:
.... эм, окей, хорошо, что я почти не пишу на C++, раз там могут наворотить такое для простенькой задачки
 

WMix

герр M:)ller
Партнер клуба
да хрена два, на плюсах ты описал совершенно другое. у тебя нет одного и тогоже метода от двух разных интерфейсов в одном классе, ты конкретно спрашиваешь у
Resolver тот или иной метод.
 

Lionishy

Новичок
WMix, прочитайте внимательно первое сообщение в теме. В С++ примере делается именно то, что должно быть.
 

hell0w0rd

Продвинутый новичок
В C++ есть перегрузка и множественное наследование. С другой стороны в php у тебя нет статической типизации и есть трейты.
Покажи реальный пример, а не котопса и давай посмотрим, как это можно сделать красиво.
 

WMix

герр M:)ller
Партнер клуба
пространство имен в PHP есть. "пространство имен методов" в плюсах я не слышал (он и так в капсуле класса)
вне зависимости, если требуется чтоб в классе Resolver метод resolveCat() возвращал другое нежеле resolveDog(), то это и так происходит. Не понимаю зачем тебе interfaces или что ты там еще себе представляешь
class RadioFacade implements IRadio
делает тоже самое!
 
Сверху