Одиночные функциональные классы (называемые глаголами)

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

Каждый класс имеет только один открытый метод (называемый "Execute"), но часто имеет закрытые методы, а иногда и конструктор с аргументами.

Примеры:

До:

class DocumentRepository {
  public List<Document> GetDocuments()
  public void SaveDocument(Document document)
  public Document CopyDocument(int id)
}

После:

class GetDocuments {
  public List<Document> Execute()
}
class SaveDocument {
  public void Execute(Document document)
}
class CopyDocument {
  public Document Execute(int id)
}

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

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

Вопрос:

Это плохая идея (как разделение, так и присвоение имен)? И если да, то как лучше создать это разделение и избежать больших классов?

Изменить: Следует отметить, что я пришел к этим (странным) идеям с точки зрения командного запроса. Поэтому, возможно, имеет смысл сравнить его с этим, а не с репозиториями.

3 ответа

Решение

Хотя выделение каждого метода в отдельный класс кажется слишком радикальным, в этом есть смысл. Для высоконагруженных систем применяется принцип разделения ответственности Command-Query (CQRS). Основная идея заключается в том, чтобы строго отделить запросы (идемпотентные методы, не изменяющие состояние системы, а только возвращающие данные) от команд (методов, которые изменяют состояние системы; в "чистых" CQRS они даже не возвращают данные - хотя это все еще мне тяжело это принять).

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

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

class GetDocumentsQuery { }

class SaveDocumentCommand { }

class CopyDocumentCommand { }

Больше информации о CQRS:

  1. https://en.wikipedia.org/wiki/Command%E2%80%93query_separation

  2. http://rob.conery.io/2014/03/04/repositories-and-unitofwork-are-not-a-good-idea/

ИМО, твой дизайн довольно странный.

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

Раньше вам нужен был только один объект, чтобы получать, сохранять и копировать документы. Теперь вам нужно 3 параллельно! Я полагаю, вы можете создать оболочку, которая обернет эти три класса,

public class DocumentRepository {
    public readonly GetDocument Get = new GetDocument();
    public readonly SaveDocument Save = new SaveDocument();
    public readonly CopyDocument Copy = new CopyDocument();
}

но все же слишком запутанный.

Если вы хотите меньше шума, постарайтесь организовать свой класс лучше и использовать #region а также #endregion если ваша IDE поддерживает их. На вашем месте я бы сделал это:

public SomeClass {
    // private fields
    ...
    // properties
    ...
    // public methods
    ...
    // private methods
    ...
}

Другой подход будет следующим:

public SomeClass {
    // private fields
    ...
    // properties
    ...
    // public method 1
    ...
    #region
    // private methods related/called by public method 1
    ...
    #endregion
    // public method 2
    ...
    #region
    // private methods related/called by public method 2
    ...
    #endregion
    // public method 3
    ...
    #region
    // private methods related/called by public method 3
    ...
    #endregion

    #region
    // other private methods that are not related to a particular public method.
    #endregion
}

Это плохая идея (как разделение, так и присвоение имен)?

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

Вы должны группировать функционально связанные методы вместе логическим способом, обычно на основе объекта, над которым он выполняет действия. Я бы сказал, что либо ваш Get, Saveи т. д. методы принадлежат к шаблонному классу репозитория или к самому классу сущностей. Никогда я не превращал бы методы в классы, это просто не имеет никакого смысла.

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

Другие вопросы по тегам