На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (495) « Первая ... 309 310 [311] 312 313 ...  494 495  ( Перейти к последнему сообщению )  
> Delphi vs C++ vs C# , ну и Java немножко, где-то ближе к старшему байту номеров страниц
    Цитата Qraizer @
    Но если придёт начальник и скажет, что заказчик передумал, и в TBC нужно разделить общий интерфейс IA так, чтобы IB и IC могли использовать разные реализации, то телодвижений для редизайна придётся сделать больше, нежели убрать virtual из базы.

    Редизайнить ничего не надо, клиентов это даже не коснётся.
    ExpandedWrap disabled
        IA = Interface
          procedure Foo;
        end;
       
        IB = Interface(IA)
          //***//
        end;
       
        IC = Interface(IA)
          //***//
        end;
       
        TBC1 = class(TInterfacedObject, IB, IC)
        private
          procedure Foo;
        end;
       
        TBC2 = class(TInterfacedObject, IB, IC)
        private
          procedure IBFoo;
          procedure ICFoo;
          procedure IB.Foo = IBFoo;
          procedure IC.Foo = ICFoo;
        end;

    Если кто забыл, TBC1 и TBC2 реализуют только интерфейсы IB и IC, указанные явно в декларации, но никак не интерфейс IA, несмотря даже на то, что он является их базовым.
    Так вот, интересно, а что будет на абстрактных классах, если мы попытаемся получить IA из "разбитой" TBC2?

    Цитата scorpion @
    DesweR, я на своей практике, как то не припомню задач, где бы мне потребовалось запрашивать интерфейс, неизвестный на этапе компиляции, у объекта, тоже неизвестного на этапе компиляции.... И главное зачем?

    Самое элементарное - фабрика.
    ExpandedWrap disabled
      type
        TFactory = class
        private
          ...
        public
          procedure Reg<T>;
          function  Get<T>: IInterface;
        end;
       
      var
        Factory: TFactory;
        A: IA;
        B: IB;
      begin
        Factory.Reg<TA>;
        Factory.Reg<TB>;
       
        A := Factory.Get<IA>;
        B := Factory.Get<IB>;
      end;


    Добавлено
    Цитата DesweR @
    Если кто забыл, TBC1 и TBC2 реализуют только интерфейсы IB и IC, указанные явно в декларации, но никак не интерфейс IA, несмотря даже на то, что он является их базовым.

    C# может получить IA из TBC1, но не сможет разбить реализацию IB и IC в TBC2.
      DesweR, и это называется "не надо редизайнить"? Как интересно. Это даже не дерево, это уже граф больше напоминает.
      Цитата DesweR @
      Самое элементарное - фабрика.
      Кстати, всё хочу спросить и всё забываю. Как в Дельфи дженерики реаизованы? Неужто байткодом?
        Цитата Qraizer @
        DesweR, и это называется "не надо редизайнить"?

        А где ты видишь редизайнище? Поправили реализацию методов в приват секции, внешние клиенты ничего не заметили.

        Цитата Qraizer @
        Кстати, всё хочу спросить и всё забываю. Как в Дельфи дженерики реаизованы? Неужто байткодом?

        А что? (если что, соглашусь псевдокод фабрики не совсем удачный)
        http://www.tdelphiblog.com/2009/10/c-c-delphiwin32.html
        Сообщение отредактировано: DesweR -
          Цитата Qraizer @
          Пока продолжу. Есть логгер ILog, который реализован в TA и TB. Оба логируют (или логгируют, как правильно?) свои действия. Наследования простые! Предположим, реализация ILog, используемая TA и TB, пишет в файл. Вопрос: файлов логов дожно быть два или один?

          Цитата Qraizer @
          Ну и собственно, почему я решил что "гвоздь". Потому что от начала и до сих пор Дельфи за программиста решает, что интерфейсы всегда совмещаются, реализации всегда разделяются. И если для интерфейсов у них ещё есть отмазка, мол, интерфейсы иначе не могут, ибо тогда они и не интерфейсы вовсе, а абстрактные классы (хотя по мне это не решение, а слив, из-за терминологической подоплёки отказаться решать практическую задачу - это моветон), то в случае реализаций и такого нет. В случае необходимости иметь различные реализации одного и того же интерфейса в одном компоненте приходится перепроектировать. Хотя наверняка это даже не замечается, а просто сразу на автомате делается по-другому, потому что простое плюсовое разделение в голову просто не приходит в связи с отсутствием поддержки в языке. В случае совмещения (возможно, частичной) реалиазций на агрегированные сущности навешивается инвариант и программируется руками. Тоже на автомате простое плюсовое совмещение ... в общем по той же причине.
          Я просто думал, мож есть какие тайные фишки. Когда речь зашла о пропертях, я ж сразу вспомнил о всяких там контейнерах типа TPanel, подумал, может там аттрибуты координат как-то связываются на языковом уровне.

          Тут всё не так просто. И надо глубоко забираться в концепции. Что у нас на входе? На входе есть некий интерфейс (пусть будет IStack), и есть его реализации. На диаграммах классов всё может выглядеть очень запутанно, но в рантайме, когда всё это "взетает", клиент интерфейса всегда работает с какой-то конкретной (финальной) реализацией интерфейса. Вот тут и начинается веселье. С точки зрения клиента всё это выглядит как? Он получает нечто (некоторый объект), и кастует его к некоторому интерфейсу (тому же IStack). Если каст проходит, то объект поддерживает этот интерфейс (читать это нужно так: "объект позволяет с собой работать в соответствии с контрактом, определенным заданным интерфейсом"). Как - клиента мало интересует. Когда есть один объект и один интерфейс, то всё просто. Когда объект поддерживает несколько интерфейсов, ситуация усложняется. Если все эти интерфейсы реализуются непосредственно финальным классом, то всё более-менее нормально. Если же автор объекта воспользовался идеей наследования реализаций, и часть видимых интерфейсов объекта реализуются на одном уровне иерархии, другая часть - на другом, возникает риск, что переход клиента от одного интерфейса к другому будет неинвариантен. Примерно так:

          ExpandedWrap disabled
            class Base1 : IDisposable
            {
            };
             
            class Base2 : Base1, ISerializable
            {
            };
             
            class Derived : Base2, IDisposable
            {
            };


          Да. Тут тот самый ромб. Предположим, клиент, получив указатель на объект класса Derived, делает такие переходы: object (Derived*) -> IDisposable (Derived*) -> ISerializable (Base2) -> IDisposable (куда?) -> ???

          Но с точки зрения логики очевидно, что во всех случаях клиент работает с финальным объектом. Он ничего не знает о его структуре. А потому переходы между интерфейсами должны быть инвариантны. Именно по этому, какая бы структура наследования не была у финального объекта, считается, что каждый интерфейс он реализует один единственный раз (в противном случае клиент очень быстро получает вынос мозга). Такая схема реализована в COM. Такая схема реализована в Delphi, С#, Java. Такая схема максимально точно реализует концепцию интерфейса как "поведенческий контракт". Именно "контракт", как "обещание вести себя строго определённым образом", и ничто другое.

          Добавлено
          Собственно, в отрыве от термина "контракт" обсуждения интерфейсов имеет мало смысла.

          Добавлено
          Цитата Qraizer @
          Одноимённость перекрытых методов не означает реализацию интерфейса.

          Вот интересно! :) На duck typing весь статический полиморфизм в плюсах работает. Собственно, а что ещё это может означать? Есть контракт поведенческой сущности "Стек", определяемой четырьмя операциями: "push", "pop", "top" и "isEmpty". Если два класса реализуют четыре этих метода, значит?.. Правильно - оба этих класса обладают поведением, соответствующим контракту "Стек". Если этот контракт зафиксирован в виде интерфейса, то совсем хорошо. :)
            Цитата Qraizer @
            Кстати, всё хочу спросить и всё забываю. Как в Дельфи дженерики реаизованы? Неужто байткодом?

            Так же как и везде, компилируются. Иначе они не нужны, есть RTTI.
            Цитата Qraizer @
            Коли речь идёт об интерфейсах, наверное, нет. Но если придёт начальник и скажет, что заказчик передумал, и в TBC нужно разделить общий интерфейс IA так, чтобы IB и IC могли использовать разные реализации, то телодвижений для редизайна придётся сделать больше, нежели убрать virtual из базы. Зато заказчик будет будет сиять от радости, если в соответствии с его пожеланиями теперь один лог валится в виндовый журнал, а второй - в файл в %APPDATA%.
            Конечно я утрирую.

            Утрируешь. На интерфейсах давно подобное делалось, подключаемые реализации. И обычно такое пишется сразу, если есть намек на изменения.
            Собственно, еще в начале века написали подключение для картридеров, любых. Там даже перекомпилировать не надо было.
              Цитата Flex Ferrum @
              Есть контракт поведенческой сущности "Стек", определяемой четырьмя операциями: "push", "pop", "top" и "isEmpty". Если два класса реализуют четыре этих метода, значит?.. Правильно - оба этих класса обладают поведением, соответствующим контракту "Стек"

              Нет, неправильно. Это означает, что совпали сигнатуры методов. Никаких "поведенческих" особенностей я из названий не вижу. Али вы уже научились семантику прямо в ЯП описывать?
                Цитата MyNameIsIgor @
                Нет, неправильно. Это означает, что совпали сигнатуры методов. Никаких "поведенческих" особенностей я из названий не вижу. Али вы уже научились семантику прямо в ЯП описывать?

                С точки зрения duck typing это именно так.
                  Цитата Flex Ferrum @
                  С точки зрения duck typing это именно так.

                  Я в курсе. Только тут обсуждается применимость уток для интерфейсов. Если решим, что применимо - тогда да, интерфейс "стек" мы реализовали. По вашим же рассуждениям "мы реализовали - значит, применимо".
                    Цитата MyNameIsIgor @
                    Нет, неправильно. Это означает, что совпали сигнатуры методов. Никаких "поведенческих" особенностей я из названий не вижу.

                    А шаблоны ты использовал? А концепты считаешь полезными?
                    В чем принципиальная разница в данном случае?
                      Цитата D_KEY @
                      А шаблоны ты использовал? А концепты считаешь полезными?

                      Да, да.
                      Цитата D_KEY @
                      В чем принципиальная разница в данном случае?

                      Чтобы задать такой вопрос, надо дождаться от меня фразы об идеальности поведения шаблонов в данном случае. Т.е. из фразы
                      Цитата Flex Ferrum @
                      На duck typing весь статический полиморфизм в плюсах работает

                      я делаю только один вывод - на duck typing весь статический полиморфизм в плюсах работает :) А вовсе не "так надо сделать всегда". Сколько там увещевали auto_ptr в контейнеры не засовывать? И только с введением rvalue reference появился смарт, который действительно туда не засунешь. Ну, не нравится мне, что вышеописанный стек от очереди (из stl) отделяет зыбкая разница в названии методов: top - front.
                        Цитата MyNameIsIgor @
                        надо дождаться от меня фразы об идеальности поведения шаблонов в данном случае.

                        А как бы ты хотел?
                          Цитата D_KEY @
                          А как бы ты хотел?

                          Чёрт возьми, хороший вопрос! Я не знаю...
                            Цитата MyNameIsIgor @
                            Цитата D_KEY @
                            А как бы ты хотел?

                            Чёрт возьми, хороший вопрос! Я не знаю...

                            Ну, например, есть вариант, что для того, чтобы можно было что-либо делать с объектом, нужно обязательно указать интерфейс типа-параметра, а если интерфейс не указан, то никаких операций с типом и объектами типа делать будет нельзя. Однако и это согласуется с duck-typing интерфейсов во время выполнения.
                              Цитата MyNameIsIgor @
                              Только тут обсуждается применимость уток для интерфейсов. Если решим, что применимо - тогда да, интерфейс "стек" мы реализовали. По вашим же рассуждениям "мы реализовали - значит, применимо".

                              Тут всё зависит от того, что считать интерфейсом. Я интерфейсом считаю фиксацию некоторого поведение. Контракт между классом и его клиентами. Поведение - это набор методов. Следовательно, если два класса предоставляют клиенту один и тот же набор методов, значит? Да. Значит, они обладают одинаковым интерфейсом. Если это семантически разные методы, об этом должно быть явным образом сообщено клиенту.
                                Цитата Flex Ferrum @
                                Если это семантически разные методы, об этом должно быть явным образом сообщено клиенту.

                                Только вот как?
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (495) « Первая ... 309 310 [311] 312 313 ...  494 495


                                Рейтинг@Mail.ru
                                [ Script execution time: 0.4766 ]   [ 15 queries used ]   [ Generated: 31.07.26, 23:24 GMT ]