Метод требует определенного подтипа, но коллекция имеет базовый абстрактный тип.Что случилось? - PullRequest
0 голосов
/ 12 июня 2018

Недавно я попал в такую ​​ситуацию.Я обобщаю проблему, потому что думаю, что она больше относится к структурному проектированию, чем к конкретной проблеме.

Общая проблема

Существует иерархия классов: абстрактный базовый класс Base инекоторые конкреции D1, D2, D3, которые наследуют его.Класс A содержит коллекцию объектов типа Base.A требует вычислений от некоторого сервиса -класса B, но метод B.process() принимает только коллекцию типа D1.Скажем, это важно, потому что, если входная коллекция содержит какой-либо другой тип, возвращаемое значение просто неверно.

Class diagram

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

Попытки, вопросы и мысли

Главной проблемой для меня была необходимость определить во время выполнения тип каждого элемента в A коллекция, так что можете отфильтровать нужные и перейти к B.process().Даже если это возможно (это в моей конкретной проблеме, более позже), это просто кажется неправильным!Я думаю, что объект, который содержит ссылки на абстрактный базовый класс, не должен знать конкретные экземпляры, которые он содержит.

Я пытаюсь:

  • Изменить тип параметра на B.process(c: Base[]) поэтому A не нужно понижать тип, но это ничего не решает: A по-прежнему необходимо фильтровать элементы, иначе вычисления будут неправильными.
  • Передайте всю коллекцию Base[] до B.process(), но просто отложите проблему выбора / понижения до B.
  • Поместите метод process() в Base, чтобы D1 мог переопределить поведение (известный полиморфизм).Проблема здесь в том, что process(), возвращающий тип SomeValue, имеет смысл только для D1.
  • Разделите интерфейс, который добавляет элементы, чтобы более специфичный метод A.addD1Element(e: D1) мог позволить поместить объекты D1в другой коллекции и передайте это B.Это должно работать, но и выглядит ... не знаю, странно.Если перегрузка метода на основе типа параметра возможна, по крайней мере, процесс не будет таким громоздким для клиентов класса.
  • Просто отделите класс D1 от иерархии.Это более агрессивный вариант предыдущего.Проблема в том, что D1 кажется связанным со всей иерархией, за исключением особых требований B.

Это были некоторые из моих мыслей по поводу проблемы.

Например, используемый язык поддерживает проверку типа объекта во время выполнения (instanceof), и коллекцию легко фильтровать на основе этой проверки.Но, как я уже сказал, мой вопрос больше связан с парадигмой.А как насчет языка, скажем, например, C ++, где менее удобно для такой проверки?

Итак, что может быть решением для такого рода проблем?Какой тип рефакторинга или шаблона проектирования может быть применен, чтобы проблема была легко решена или просто исчезла?

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

Контекст (проблема в действии)

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

Имеющаяся проблема похожа наэто:

A - это класс (некая сущность, например, DDD), которая моделирует своего рода соглашение или долг , которые клиент берет на себя за услугу.Он имеет разные расходы, включая ежемесячную оплату.Base и смежные классы - это платежи разных типов.Они имеют много общего, хотя в основном это данные (дата, количество, интересы и т. Д.);но есть по крайней мере один тип платежа, который имеет другую дополнительную информацию: ежемесячный платеж (D1).Эти платежи необходимо тщательно проанализировать, чтобы за это отвечал другой класс (B), используя больше контекстной информации и все платежи этого типа одновременно.Службе нужны дополнительные данные, относящиеся к этим платежам, поэтому они не могут получить абстрактный тип Payment (по крайней мере, в этом дизайне).Другие платежи не имеют конкретной информации, которую MonthlyPayment имеет, и поэтому они не могут генерировать значения, которые требуются бизнесу, и B генерирует (не имеет смысла в других типах платежей).

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

В основном это контекст.Я думаю, что дизайн не самый лучший, но я не вижу лучшего.

Может быть, выделение только MonthlyPayment (D1) в другой коллекции, как описано ранее?Но это не единственный платеж, который требует дополнительной обработки (хотя он и самый сложный), поэтому я мог бы закончить с разными коллекциями для каждого типа платежа и без какой-либо иерархии.В настоящее время существует четыре типа платежей, и два из них требуют дополнительного, особого анализа, но позже можно добавить больше типов, и проблема необходимости изменять реализацию при каждом добавлении нового типа сохраняется.

Является ли это, более дискретный подход разных коллекций по типу, лучше здесь?Абстрактный базовый класс Payment все еще может использоваться для платежей, которыми можно манипулировать через общий интерфейс.Также я могу использовать супертип layer или что-то в этом роде, чтобы разрешить повторное использование общей функциональности (язык также допускает разновидность смешивания ) и прекратить использование базового класса в качестве пользователя root отиерархия.

Уф.Я прошу прощения за длину текста.Надеюсь, это хотя бы читабельно и понятно.Заранее большое спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...