Как стать автором
Обновить

Комментарии 13

В Lisp объектная модель пошла по другой "ветке развития", там у классов нет методов в понимании C++ или Java, а просто определяются функции с явным указанием типов параметров:

(defmethod render ((w widget))
  (error "Don't know, how to render a widget, please define a render for your subclass!"))

(defmethod render ((b button))
  (render a button))

(defmethod render ((c checkbox))
  (render a checkbox))

(defmethod dump ((w widget) stream)
  (format stream "Dump of ~A widget" (class-name (class-of w))))

(defmethod dump ((c checkbox) stream)
  (format stream "Dump of checkbox ~A" (name c))
  (call-next-method)) ;; Тут будет вызван метод для widget с теми же параметрами

То есть мы просто объявляем новые функции через defmethod , а компилятор уже сам будет решать, какую из них вызывать, в зависимости от типа параметров. Да, можно указать несколько параметров с разными типами.

А можно проверить в compile-time, что у всех виджетов, которые рендерим, есть соответствующий метод?

Это зависит от реализации компилятора, не все они поддерживают вывод типов на этапе компиляции. Кроме того, для лиспа нормальной практикой является самомодифицирующийся во время исполнения код (сейчас, в несколько урезанном виде, это известно как JIT), так что новые методы вполне легально могут появляться уже во время исполнения программы. Впрочем, стандарт языка позволяет влиять на процесс компиляции средствами самого же языка, так что существует, например, библиотека, которая делает как раз искомое. Подключаете ее и у вас методы компилируются статически, если удается определить тип параметра на этапе компиляции.

Насколько я понял какая-то ключевая идея статьи должна была быть в параграфе:

Object Algebra

но, там ничего нет про "Algebra" кроме невнятного

Объектной алгеброй назовем класс, имплементирующий сигнатуру.

, более того параграф заканчивается многообещающе:

такой код просто не скомпилируется.

Интересно это издевательство над Хабром или над читателями Хабра, или над обоими?

Эти проблемы давно уже решил Дядя Боб и формализовано в SOLID. Реализовывается с помощью Dependency Inversion и таких фреймворках, как Spring.

    abstract class Widget {
        
    }
    
    class Text extends Widget {
        private String text;
        public Text(String text) {
            this.text = text;
        }
        public String getText() {
            return text;
        }
    }
    
    class Button extends Widget {
        private int roundCorner;

        public Button(int roundCorner) {
            this.roundCorner = roundCorner;
        }

        public int getRoundCorner() {
            return roundCorner;
        }
    }
    
    interface Renderer {
        void render(Widget widget);
    }
    
    class RendererScreen implements Renderer {
        private Screen screen;

        public RendererScreen(Screen screen) {
            this.screen = screen;
        }

        @Override
        public void render(Widget widget) {
            //... do somethind to screen
        }
    }
    
    class RendererWeb implements Renderer {
        private OutputStream outputStream;

        public RendererWeb(OutputStream outputStream) {
            this.outputStream = outputStream;
        }

        @Override
        public void render(Widget widget) {
            // ... do somethins to stream
        }
    }

А что внутри public void render(Widget widget)? switch по типу виджета с разной логикой для кнопок/текста/etc?

а у Widget нельзя определить виртуальную функцию которую будут переопределять наследники для кнопок/текста/etc ?

Тогда

внутри public void render(Widget widget)?

будет только вызов этой виртуальной функции вроде как, так не получается? Насколько я помню это вроде как про Composer, но не уверен что это нужное слово или полное название, лень искать ПДФку.

Возможно будет проще (а значит правильнее) вызывать эту виртуальную функцию ВМЕСТО вызова public void render(Widget widget)

Можно. Но тогда по сути, это будет первый кейс описаный в статье, с теми же проблемами

а у Widget нельзя определить виртуальную функцию которую будут переопределять наследники для кнопок/текста/etc

Хотелось бы, чтобы Widget (Text, Checkbox, ...) ничего не знал о процессах, которые можно с ним делать (Render, Dump, ...). То есть, всё такие комбинации были вынесены из классов в отдельные функции

void Render(Screen s, Text t);
void Render(Screen s, CheckBox c);
void Dump(Logger dst, Text t);
void Dump(Logger dst, CheckBox c);

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

Классическая проблема, имя её - двойная диспетчеризация или мультиметод

вы либо сами запутались, либо меня хотите запутать: по этим ссылкам предлагается определить операции для объектов-наследников одного базового класса, из одной иерархии, а в этом примере:

void Render(Screen s, Text t);
void Render(Screen s, CheckBox c);
void Dump(Logger dst, Text t);
void Dump(Logger dst, CheckBox c);

у нас объекты из разных иерархий Screen и Logger не родственники Text-у и CheckBox-у.

Хотелось бы, чтобы Widget (Text, Checkbox, ...) ничего не знал о процессах, которые можно с ним делать (Render, Dump, ...)

мне кажется мотивация в стиле "хотелось бы" не самая конструктивная в практическом программировании, если мы конечно обсуждаем проблемы именно практического программирования.

Я кстати посмотрел работу банды четырех, шаблон проектирования который я имел ввиду называется Composite pattern, а чтобы добавлять метод в дочерние классы также подходит ADAPTER например, но надо конечно соотносить выбор подходящего шаблона с конкретной задачей взаимодействия объектов, потому что создавать классы для хранения названий цветов это конечно не задача.

Как ни странно то что написали банда четырех до сих пор работает на миллионах ПК как раз для визуальных объектов. Чтобы придумывать что-то свое неплохо бы освоить сначала то, что уже вполне эффективно работает.

Не вижу принципиальной разницы между диспетчеризацией

void Render(Screen s, Text t);

и

void Collide(Asteroid a, Planet b);

Тогда по сути это особо и не отличается от visitor

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории