Вопрос по интерфейсам и фабрике обьектов.

hgjtfrdredreder

Путник
Участник
Сообщения
90
Розыгрыши
0
Репутация
-16
Реакции
32
Баллы
46
Хроники
  1. Chaotic Throne: High Five
Исходники
Присутствуют
Сборка
L2J
Возможно это не совсем адекватный вопрос)

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

И еще глупый вопрос - насколько ресурсоемок каст интерфейса к имплементации? Еслть смысл на это обращать внимание или накладные расходы ничтожны. Чет не смог нагуглить.
 
Проблема немного наизнанку. Что-бы знать что должно быть в интерфейсе, нужнo найти код где все обьекты уже используються, ну и описать функции интерфейса. Ну а потом будет вопрос зачем там интерфейс.... Обычно он нужен где нужно прикрыть доступ к множеству функций и ограничить все через функции интерфейса. Почему? A что-бы гарантировать что-бы код мог работать только со специальными обьектами, построенными через такой вот интерфейс.

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

Идея заключается в том, чтобы с помощью интерфейсов как раз таки уменьшить зоопарк классов в основной части кода, подтянуть архитектуру. Зачем импортировать 10 родственных имплементаций, переопределяющих по своему методы родителя, там, где по хорошему должно хватать одного родительского интерфейса, например.
 
Переменные можно и без геттеров/сеттеров использовать. Вот так все просто. Но всем как-то хочется все спрятать в дополнительный уровень абстрации. Можно? Конечно, вперед...

Нужно сформулировать проблему. Ну например, вот так-то плохо, а будет намного удобнее если интерфейс там будет. А так просто без конкретного примера говорить можно без остановки. Вот в чем заключается зоопарк классов? В их количестве? Или же не нравится что один класс больше чем другой? Или же хочется как-то все это раздробить в более мелкие классы? И в чем будет лучше?
 
Я что-то не пойму как Вы собираетесь интерфейсами все заменить...

Условно в интерфейсе только финальные и статические классы есть. То-есть условно из текущего

Java:
private ClassId _classId;

public void setClassId(ClassId classId)
{
    _classId = classId;
}

вы собираетесь сделать

Java:
private final ClassId _classId;

public void setClassId(ClassId classId)
{
    _classId.setClassId(classId)
}

в таком случае нужно как минимум запрет на чтение дополнительно вешать, или реализовывать как

Java:
public abstract void setClassId(ClassId classId);

private ClassId _classId;

@Override
public void setClassId(ClassId classId)
{
    _classId = classId;
}

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

Не догнал пример. Зачем использовать внутри класса его же сеттер? Мож я туплю на ночь, сори)
 
Ну я когда начал портировать NASC к себе, столкнулся с тем, что гораздо проще какие-то вещи упаковать в интерфейсы и работать с ними. Я решал таким образом проблему отсутствия множественного наследования, которого нет в Java, но которое есть в C++.
Но все подряд пихать в интерфейсы - смысла нет на самом деле. На вашем месте, я бы начал перепиливание архитектуры L2j с внимательного изучения структуры слитого ПТС. Иначе просто перепилив лыжу в то, что вам кажется верным, на выходе получится ублюдок-мутант, который кроме вас не будет никому нужен. И когда вы столкнетесь с вопросом: "Вот я написал распиздатый движок, но почему-то, чтобы заставить его работать как нужно, мне придется опять перепилить его в фабрику костылей." - будет уже поздно)
 
Спасибо, теперь мои дела пойдут в гору!
Я решаю проблему исправления архитектуры в данном случае. Интерфейсы повысят уровень абстракции и обяжут искать более правильные и красивые решения, а не пилить из говна и палок нечто "главное что работает". Может не совсем уж всё - некоторые классы не нуждаются в интерфейсах, очевидно.
Ну вот я и решил посоветоваться)
 
Я решаю проблему исправления архитектуры в данном случае
Вам правильно написали. Сформулируйте конкретную проблему, желательно с примером кода и опишите, как конкретно экстракция интерфейса поможет ее решить. Я не сильно чет могу представить кейс в котором бы это имело смысл в лыже, в контексте ее структуры. И избегайте использовать слово “архитектура”, чтобы не навлечь на себя гнев Rozhek
 


Есть вот такое дерево классов. Оно не полное - там ниже еще инстансы и прочее. Что мы имеем:
1. Корабли наследуются от Character. Почему? Потому что логика движения реализована там, а не в корневом обьекте.
2. Сам Character 10к строк. При том, что часть его методов можно пихнуть в родительский обьект (и отнаследовать корабль от него), а часть вроде как вообще в потомков перенести.
3. Типичное использование в коде примерно такое:
Java:
private PCInstance player;

public void foo(PCInstance p, AVehicle v, Location loc) {
    p.moveTo(loc);
    v.moveTo(loc);
    player = p;
}

public PCInstance get() {
    return player;
}

Зачем тут имплементация, если код moveTo реализован будет в AObject вообще?
Почему не сделать так? Количество сущностей мгновенно сократилось, абстракция повысилась. Оккама одобряе.

Java:
private IObject player;

public void foo(IObject p, IObject v, ILocation loc) {
    p.moveTo(loc);
    v.moveTo(loc);
    this.player = p;
}


public IObject get() {
    return player;
}

// допустим это некий метод обработки игрока
// и мы знаем, что тут прилетает PCInstance
private void doWithPlayer() {
    IObject p = this.get();
    ((IPCInstance) p).doSmth()
}

Мне кажется такой подход поможет привести классы в порядок в процессе приведения их к минимальному количеству интерфейсов.

4. Ещё там есть класс L2Item. Финализированый. То есть он описывает вообще любой айтем. В нём полей 50 наверно. Этому конкретному предмету нужно только 2 поля из 50? [А по щам?] там - он будет хранить все 50.

Мне кажется, что повысив уровень абстракции в процессе пиления интерфейсов мне станет лучше понятно как распределить методы по родителям/наследникам/сиблингам, где может добавить сущностей, где наоборот убрать. А сейчас это дом из говна и палок - одну убираешь и за ней падает к хуям всё вообще по цепочке.
 
1. Корабли наследуются от Character. Почему?
Потому, что корабль это прежде всего сущность и кроме движения, он обладает другими признаками сущности, как-то параметры(скорость, колизии), ИИ и самое важное - способностью слать игрокам о себе информацию, используя сетевые пакеты. Вы будете удивлены, но кубики и агатионы это тоже сущности.

2. Сам Character 10к строк.
Вам смущает количество строк? Почему? Вы можете попробовать сделать грамотную декомпозицию классов Character и Player, но для этого нужно понимать причины, вызвавшие такой размер и я не уверен, что среди этих 10000 строк вы найдете дубликаты кода для более чем 5%(Более того, когда к вам придет осознание того, что APlayble не должно существовать в принципе, эти классы прирастут еще 2-3к строк каждый) А также, в какие-то моменты опять же удобнее обратиться напрямую к родительскому типу сущности, чем делать очередной каст к нужному типу наследника, что в очередной раз снижает когнитивную нагрузку. Да и 10к строк там на самом деле не потому, что разработчики лыжи неквалифицированные идиоты, которые не понимают как писать код.
Субъективщина. Мне например, более удобно когда основные проверки и часть логики предмета в одном классе, а не размазана на 20 слоев абстракций, т.к это снижает когнитивную нагрузку и прыгать в дебагере по десятку классов вместо одного метода - такое себе удовольствие. Кроме того, с постепенным узнаванием структуры лыжного ядра, вы поймете, что если в XML описано 2-3 поля итема, не означает, что у него 2-3 свойства, а означает, что остальные 50 полей имеют значение заданное по умолчанию.
 
Последнее редактирование:
Ну так всё это добро наследуется от L2Object - почему не реализовать все базовые для всех обьектов механики там? Это сразу разгрузит L2Character и позволит реализовать общий интерфейс IObject с общими для всех обьектов свойствами. А в L2Character оставить то, что характерно персонажам - скилы etc.
Отсылка пакетов вообще реализуется в потомках с третьего колена вроде - тех, которых нет на диаграмме как раз, и эти методы легко и непринуждённо становятся абстрактными, что превращает L2Object в AObject, что и верно, по сути.
Разработчики не идиоты, но их много и коду дохерища лет - он прошел через кучу хроник. И постоянно там что-то пилили и пилят разные люди, что в принципе лишает возможности заняться рефакторингом. Там, например, хватает методов с пометкой Deprecated и TODO:delete this. Декомпозицию классов тоже начинаю делать. Например, кажется, в Character куча думми методов, что явно намекает на косяк в архитектуре в этой части кода - как минимум их можно безболезненно вынести в отдельный подкласс не нарушив структуры. Хотя правильнее будет вынести их в потомков, скорее всего.
В том то и дело, что имеют заданное по умолчанию. Но оно не используется, а тупо висит в памяти. А обьектов то много. Хотя я глянул, и наверно это был не Item, а что-то другое. Хотя его тоже можно разбить на отнаследованные подклассы, мне кажется.

Вот нафига, допустим, квест итему большая часть этих полей? Хз. Они просто есть.
 
Так а конечная цель какая все же?
Но оно не используется, а тупо висит в памяти. А обьектов то много.
Снизить потребление памяти? На сколько? Вдвое? Втрое? Вероятно, счет будет идти в лучшем случае - на ДЕСЯТКИ(в лучшем случае ПАРУ СОТЕН) МЕГАбайт. Как вы думаете, два бакса в месяц переплаты за впс стоят пары месяцев вашей работы?


Сделать все академически и эстетически красиво? Ну тогда вам проще писать сразу с нуля, т.к это займет намного меньше времени, чем стабилизировать и причесывать лыжу, т.к там очень много ГЛОБАЛЬНЫХ проебов, об которые вы будет раз за разом убиваться и перед вами будет вставать выбор - переписать вот этот ахуенно огромный глобальный механизм, который тянется через все ядро и прорастает БУКВАЛЬНО В КАЖДЫЙ другой крупный механизм, попутно сломав кучу всего, выбив из под этого костыли, либо сказать - да ну нах, я быстрее с нуля это напишу.
 
Так а конечная цель какая все же?
Сейчас хотя бы минимально структурировать код и подготовить его к более глубокой переработке. Сейчас это невозможно - тронул одно и будешь переписывать вообще всё. Для этого я и пытаюсь повысить уровень абстракции - уменьшить количество сущностей, структурировать, сделать логичным. Программирование как математика - правильно то, что красиво, и красиво то, что правильно. Глобально - хочу сделать правильно.
Моё самоуважение и гордость от хорошо проделанной работы этого стоят)
Проще, но не мне, к сожалению. Я никогда не писал серверов и на яве тоже. Спасает только то, что она Си-подобная) Я не знаю как должно быть правильно, но жопой чую, когда не правильно - от этого и пляшу. Так бы конечно лучше сам написал, но это вообще первый проект с таким количеством кодовой базы для меня. С нуля я такое не вывезу - придётся шаг за шагом делать маленькие уборочки то тут, то там, и постепенно исправлять проёбы от меньшего к большему.

Собственно потому я и спрашивал насчет фабрики обьектов. С таким подходом я в один клик через глобальный поиск ИДЕшки мог бы найти все создания обьектов в коде и держать всю имплементацию на виду, а не размазаной тонким слоем по коду, а в коде работать с достаточно ограниченным количеством интерфейсов - это бы дало чуть больше контроля и в последствии бы пригодилось. Но я не уверен, как это будет работать в многопоточности - плохо знаю язык.
 
Весь этот перфекционизм в "вылизывании" кода к сожалению возможен только если у тебя просто дохренища свободного времени и более заняться нечем...
А если у тебя ситуация "это все должно было работать еще вчера", то увы на "сделать все красиво" зачастую просто нет никакого времени.
Я вон тоже периодически порываюсь многое у себя в сервере переделать в плане структуры кода, но где на это найти время? Игроки у меня уж точно не будут ждать еще несколько лет, когда я весь сервер "по фэншую" перепишу. Так что большей частью приходится обходиться относительно точечными переделками...
 
Последнее редактирование:
При этом игрокам глубоко "насрать" как написано код - "по фэншую", или в момент снюхивания кокса с соска проститутки, где потом сам разобраться не можешь, если оно работает - то какая разница как оно написано
 
Это да, но у меня есть некоторое количество времени на это. И я надеюсь в последствии отбить потраченное за счет более легкой и быстрой разработки) К тому же мне так и так необходимо перелопатить весь сервак чтобы понять как он работает - рефакторинг отличный способ это сделать, мне кажется)
 
В целом разделение ответственности хорошая практика, как минимум можно будет нормально покрыть тестами логику. Если нет других целей, помимо цели ”сделать красивее”, рекомендую посмотреть в сторону тестирования