Способ проектирования структуры классов - PullRequest
2 голосов
/ 29 апреля 2019

У меня очень простая структура классов. Классы B и C наследуются от A. Функциональность аналогична в случае некоторых функций и свойств. Классы B и C по-разному обрабатывают данные, но классы имеют одинаковый вывод (функция, создающая вывод, находится внутри класса A). Пример структуры: enter image description here

Теперь мне нужно расширить функционал. Мне нужно добавить опцию для небольших различий в обработке и выводе данных (класс X). Эта опция управляется файлом конфигурации, поэтому я хочу сохранить старый способ загрузки, обработки и вывода данных, например ::10000

  1. опция 1 - загрузка данных без потоков с использованием старого способа обработки и вывода
  2. опция 2 - загрузка данных без потоков с использованием нового способа обработки и вывода
  3. опция 3 - загрузка данных с потоков с использованием старого способа обработки и вывода
  4. опция 4 - загрузка данных без потоков с использованием нового способа обработки и вывода

Я не уверен, как реализовать комбинацию новой обработки и вывода данных. Мне нужна комбинация класса B и X (BX) и класса C и X (CX). Я думаю об этих вариантах:

  1. Самый простой, но худший способ - дублирование некоторых функций в классе B и классе A.
  2. Сохраните классы A и B и добавьте комбинацию классов BX и AX.
  3. Переписывайте классы A и B только для загрузки данных. Затем добавьте классы для обработки данных, а затем добавьте классы для вывода данных. Все классы будут делиться объектами. Похоже, лучший вариант, но с большей работой.

Есть ли лучший вариант (например, шаблон проектирования или что-то в этом роде), как расширить классы самым чистым способом?

Ответы [ 2 ]

3 голосов
/ 29 апреля 2019

Мне кажется, что у вас есть Поток данных .

Что у вас есть Получить (загрузить) данные -> Данные процесса -> Выходные данные . В основном это конвейер с тремя этапами.

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

Позволяет использовать три интерфейса (вы можете использовать абстрактные классы для их определения, это не имеет значения) для определения шагов конвейера: IDataDownloader , IDataProcessor и IDataOutputer .

Позволяет добавить еще один объект, который будет представлять и управлять конвейером:

(Примечание: у меня нет опыта работы с Python, поэтому я напишу его на C # извините ..)

public class Pipeline {

  private IDataDownloader mDataDownloader;
  private IDataProcessor mDataProcessor;
  private IDataOutputer mDataOutputer;

  public void Setup() {

    // use a config file to select between the two ways

    if (Config.UseOldWayDownloader) {
      mDataDownloader = new OldWayDownloader();
    }
    else {
      mDataDownloader = new NewWayDownloader();
    }
    // ....

    // or you can use service locator or dependecy injection that will get
    // a specific downloader based on configuration/setup

    mDataDownloader = Services.Get<IDataDownloader>();
    // ....
  }

  public void Execute() {

    var data = mDownloader.Download();

    var processedData = mDataProcessor.Process(data);

    mDataOutputer.Output(processedData);
  }
}

Таким образом, вы получаете хорошее разделение интересов и получаете модульную систему, которую вы можете расширять. Эта система также является составной. Вы можете составлять его части по-разному.

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

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

Одним из примеров этого является случай со свободными типизированными языками. Довольно часто вы пишете меньше кода, поэтому он быстрее, но он подвержен ошибкам из-за ошибок. В случае ошибки вы получаете более (а иногда и более сложную) отладку, поэтому вы тратите время.

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

Чтобы гарантировать надежность вашего программного обеспечения, вам нужно написать больше тестов и больше проверок / утверждений, чтобы убедиться, что все работает гладко. Таким образом, в конечном итоге вы, вероятно, получите такой же объем кода, что строгая типизация выполняет некоторые проверки для вас, и вы можете написать меньше тестов.

Так что лучше? Ну ... это зависит.

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

Скорость может быть разной, но это не всегда так, иногда просто так.

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

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

2 голосов
/ 29 апреля 2019

Ну, чтобы сделать ответ UML, я добавляю диаграмму классов:

enter image description here

Pipeline имеет те три класса обработки.Все они абстрактны, поэтому вам нужно будет реализовать их по-разному.И configuration назначит их в соответствии с тем, что говорится в конфигурации (файле).

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