как продолжение моего предыдущий вопрос Наличие функции с комбинированными общими границами, такими как:
<T extends Foo & Bar> void doStuff(T argument) {
//do stuff wich should only be done if arguments is both foo and bar
}
Поскольку это не может быть приведено из неопределенного объекта, вам необходимо знать какой-то объект, который фактически реализует эти интерфейсы. Мне кажется, что необходимость знать конкретный тип аргумента объекта для передачи в doStuff(T a) является нарушением закона Деметры.
Функция не указывает, что необходимо знать фактический класс (может быть много разных), и я действительно не хочу знать об этом, поскольку знание этого класса увеличивает зависимость в моей базе кода.
использует эти границы как антипаттерн? и если да, то как лучше всего этого избежать?
сценарий случая включал один интерфейс, определяющий, что объект является постоянным, а другой указанный объект имел связанную сущность. функция doStuff(T a) в этом случае сохранила связанный объект, когда он был сохранен. однако непостоянные объекты также могут иметь связанные объекты, но не должны обрабатываться функцией doStuff(T a).
это так, но я подумал, что для ясности было бы лучше сделать это другим вопросом
Ну, вы, очевидно, все об этом знали, я просто думал обо всех, кому может понадобиться больше контекста :)




Я бы не стал рассматривать комбинированные общие границы как антипаттерн. По крайней мере, у меня есть несколько вариантов их использования в моем коде. Например, следующий пример кода находит самый большой экземпляр Number в коллекции с помощью compareTo из интерфейса Comparable:
<T extends Number & Comparable<T>> T max(Collection<T> numbers)
Зачем T нужно продлевать номер? Не работает ли он на полностью заказанном типе?
Number на самом деле имеет значение для стертой подписи метода (он вернет Number вместо Comparable). В более общих Collections.max он возвращает T extends Object & Comparable <? super T>, это потому, что метод до версии 1.5 возвращал Object вместо Comparable.
it seems to me that needing to know the specific type of the object argument to pass to doStuff(T a) is a violation of Demeter's law
Я не согласен. Я не понимаю как
T<? extends Foo & Bar> void doStuff(T argument)
требует дополнительных знаний аргумента для передачи, затем
T<? extends Foo> void doStuff(T argument)
Или даже больше, чем просто
void doStuff(T argument)
Во всех случаях вам нужно что-то знать об аргументе, и я не думаю, что в первых случаях требуется больше знаний, чем в других, потому что у них есть два идентификатора.
потому что в первом примере нам нужно явно передать некоторый класс A, реализующий Foo, bar, что означает, что нам нужно знать класс A, а во втором примере нам нужно знать только ИНТЕРФЕЙС Foo (не класс B реализует Foo)
Антипаттерн - это литье.
Тем не менее, причудливая работа с дженериками может сбивать с толку неопытных программистов. Использование таких типов и методов должно быть намного проще, чем их реализация.
Этот вопрос кажется связанным с вопросом преобразовать в комбинированный универсальный (того же автора).