final по дефолту

grigori

( ͡° ͜ʖ ͡°)
Команда форума
что мешает lazy load делать с помощью механизма описанного в вики про proxy?
Что мешает называть меня Вася? Ничего. В этом просто нет смысла, но не мешает ничего.

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

Если мы обсуждаем паттерны - мы подразумеваем задокументированный алгоритм. От возраста алгоритм не зависит.

Если реализуем lazy loading как proxy - это будет proxy, а не lazy loading.
А писать код как угодно - ничего не мешает.
 
Последнее редактирование:

Adelf

Administrator
Команда форума
Не знал что такой прям паттерн даже есть. Lazy loading.
Прочитал. По первой же ссылке:
Существует четыре основных варианта ленивой загрузки.
  • Virtual Proxy (Виртуальный Прокси) - объект с таким же интерфейсом, как и настоящий объект. При первом обращении к методу объекта, виртуальный прокси загружает настоящий объект и перенаправляет выполнение.
Т.е. вполне все реализуется. Без наследования.

Просто исходя из этого сообщения:
технической необходимости наследования в случае с proxy не то что нет, а не должно быть по определению

а вот с lazy load - конечно, для этого наследование и создано
Я понял, что без наследования при lazy loading не обойтись. Что не является правдой.
 

Вурдалак

I'd like to model your domain
Очередной тред скатился в какой-то срач на тему того, что же там написано в этой старой книжке из 90-х годов, в то время как основной пойнт «отсутствие final у моделей — хак» был тупо не понят. Впрочем, с Гришей любой диалог примерно так и выглядит.
 

fixxxer

К.О.
Партнер клуба
с duck typing в golang/typescript
Я уже говорил, но повторюсь. Duck typing - это в python (no typing is duck typing).

Duck typing is similar to, but distinct from structural typing. Structural typing is a static typing system that determines type compatibility and equivalence by a type's structure, whereas duck typing is dynamic and determines type compatibility by only that part of a type's structure that is accessed during run time. (Wikipedia).

В golang и typescript - structural typing. И он проблему не решает.

Например, такой код в typescript не скомпилируется (в typescript нет final из-за сложностей с реализацией final method, но сути это не меняет):

PHP:
class Foo {
    public someMethod(): void {
    }

    private somePrivateMethod(): void {
    }
}

class Bar implements Foo {
    public someMethod(): void {
    }
}
Код:
$ tsc test.ts
test.ts:9:7 - error TS2720: Class 'Bar' incorrectly implements class 'Foo'. Did you mean to extend 'Foo' and inherit its members as a subclass?
  Property 'somePrivateMethod' is missing in type 'Bar'.
Может показаться, что такое поведение компилятора ничем не оправдано и следовало бы позволить такому коду компилироваться. Но в этом случае будет проблема с таким кейсом:

PHP:
class Foo {
    public someMethod(foo: Foo): void {
       foo.somePrivateMethod();
    }

    private somePrivateMethod(): void {
    }
}
Если пример выглядит надуманным - пусть будет не someMethod(), а equals().

Так что с подходом "разрешим имплементить фактический интерфейс без наследования" тоже все не так просто.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Я уже говорил, но повторюсь. Duck typing - это в python (no typing is duck typing).

В golang и typescript - structural typing. И он проблему не решает.
OK, авторы TypeScript придерживаются несколько иного представления, но терминология - не столь важно
https://www.typescriptlang.org/docs/handbook/interfaces.html
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
«отсутствие final у моделей — хак» - я увидел, конечно, вы раза три это написали, но мне нечего сказать
хак - он и есть хак, мне он не нравится
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
@fixxxer, в golang приватных свойств как таковых нет - все рассматривается в контексте пакетов, и простая реализация свойств интерфейса вполне работает
https://golang.org/ref/spec#Interface_types
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
Go слишком далек по дизайну от языков с Java-подобным ООП, чтобы можно было делать сколь-либо корректные сравнения. Но отдаленную аналогию провести можно:если написать typedef Foo Bar, то Foo и Bar не будут взаимозаменяемы, а вводить интерфейс - для сущности явно излишне: код вида type User struct {...}, type UserInterface interface {...} выглядит столь же неуместно, сколько и class User implements UserInteface.

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

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Если, например, научить Doctrine-овский ProxyManager делать прокси, привязанные к заданному в конфигурации интерфейсу, то проблема с final решится - но возникает проблема с тем, что интерфейс для сущности не нужен и вреден.
да, как в Laravel
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
в общем, делать классы final - полезно, но часто это вступает в противоречие с некоторыми общепринятыми паттернами

почему я перешел к обсуждению паттернов - это потому что я не использую доктрину, и думаю, как лучше делать слой работы с базой в новом сервисе, который сейчас начинаю писать
проще всего отказаться от lazy load - он нужен, в основном, в автогенерируемом ORM,
с моками сложнее - можно добавить uopz в образ
интерфейсы для сущностей - не вариант, конечно
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
Lazy load, по большому счету, нафиг не нужен.

Моки обычно нужны только на инфраструктурные вещи, а там есть интерфейс. Если очень хочется, можно и uopz втащить, на CI-машинке он никому не помешает; но вообще архитектура, в которой требуется мокать сущности, выглядит странно.
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Да, я тоже так думаю: когда хочется сделать прокси, стоит выделить интерфейс, потому что обычно это нужно служебным классам. Случай, в котором нужен мок без интерфейса, я придумать сходу не могу - но я могу чего-то не учитывать.
 

ivanov77

Новичок
В теории звучит неплохо, но на практике..
Например в Yii, надо нам какой то свой класс создать:
- свой контроллер наследуем от базового контроллера
- свой валидатор от базового
- свою модель от базовой модели
- AR от AR
- и т.д.
И это все понятно без сложности, в том числе новичкам. В том что чтобы получить в руки объект нужной функциональности мы наследуемся от нужной функциональности.
Или это тот случай когда они "подходят под наследование"?

А когда композицией один объект обращается за сервисом к другому, в голове представляется совсем другое а не отношение is_a.
А они начинают вот эти свои советики обобщать и например на ListView переносить, а как оно красиво получится, когда один объект начнет разбирать результаты работы другого объекта, какие форматы для этого потребуются (вот html уж совсем не захочется парсить) , сколько надо методов открыть как public.
 

fixxxer

К.О.
Партнер клуба
@ivanov77, во всех этих случаях ты наследуешься от абстрактного класса. Это нормально.

Смысл в том, что класс либо abstract, либо final. Всегда, когда тебе надо отнаследоваться не от абстрактного класса, это признак архитектурной проблемы (либо вынужденный инфраструктурный костыль, как в случае с Doctrine).
 

fixxxer

К.О.
Партнер клуба
авторы TypeScript придерживаются несколько иного представления
Они просто не стали в рамках базовой документации излишне углубляться. Я уверен, что Anders Hejlsberg понимает разницу.
Duck typing в ts тоже есть, в той же мере, в какой он есть в php: type hinting опционален, причем в обоих случаях это сделано прежде всего для обратной совместимости. Но мы же не хотим так писать, правда?
 
Последнее редактирование:

ivanov77

Новичок
базовый == абстрактный.
Тут это не абстрактные классы.
При наследовании от неабстрактного вы вот это вот из DIP
Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.
интерпретируете как зависимость от неабстракции (неабстрактного класса)?
 

fixxxer

К.О.
Партнер клуба
В случае с контроллерами и прочими валидаторами это на самом деле не является проблемой - они инстанциируются 1 раз, вызывается 1-2 метода, и на этом все: инстанс больше не используется, ссылка на объект никуда не передается и т.д. Тут вообще можно сделать какую угодно фигню, по большому счету, тут ООП-конструкциями эмулируется некий декларативный язык, а методы - чистая процедурщина. Вообще по барабану, нерелевантно.

Рельсоподобный Active Record же я вообще не хочу обсуждать в стомиллионный раз, поскольку там антипаттерн на антипаттерне. Там, конечно, должен быть абстрактный класс, но если даже это не так, пофигу, потому что это просто говно.

Да вообще про Yii говорить неинтересно: все, что я на нем видел, было процедурным кодом, обернутым в классы. (На Laravel, впрочем, в большинстве случаев так же).
 
Последнее редактирование:
Сверху