Рассмотрите следующий класс
public class Class1
{
public int A { get; set; }
public int B { get; set; }
public int GetComplexResult()
{
return A + B;
}
}
Для использования GetComplexResult
, потребитель этого класса должен был бы знать для установки A
и B
прежде, чем назвать метод. Если GetComplexResult
доступы много свойств для вычисления его результата это может привести к неправильным возвращаемым значениям, если потребитель не устанавливает все соответствующие свойства сначала. Таким образом, Вы могли бы записать этот класс как это вместо этого
public class Class2
{
public int A { get; set; }
public int B { get; set; }
public int GetComplexResult(int a, int b)
{
return a + b;
}
}
Таким образом, вызывающая сторона к GetComplexResult
вынужден передать во всех необходимых значениях, гарантировав, что значение ожидаемого дохода правильно вычисляется. Но если существует много необходимых значений, список параметров растет также, и это не походит на хороший дизайн также. Это также, кажется, повреждает точку инкапсуляции A
, B
и GetComplexResult
в едином классе. Я мог бы даже испытать желание сделать GetComplexResult
статичный, так как это не требует, чтобы экземпляр класса сделал свою работу. Я не хочу обходить создание набора статических методов.
Там называет, должны описать эти 2 различных способа создать классы? У них обоих, кажется, есть за и против - там что-то, что я не понимаю, что это должно сказать мне, что один путь лучше, чем другой? Как поблочное тестирование влияет на этот выбор?
Если вы воспользуетесь реальным примером, ответ станет более ясным.
public class person
{
public string firstName { get; set; }
public string lastName { get; set; }
public string getFullName()
{
return firstName + " " + lastName;
}
}
Суть объекта сущности в том, что он содержит информацию о сущности и может выполнять операции, которые сущность должна выполнять (на основе информации, которую он содержит). Итак, да, есть ситуации, в которых определенные операции не будут работать должным образом, потому что объект не был полностью инициализирован, но это не ошибка дизайна. Если в реальном мире я прошу вас назвать полное имя новорожденного, которого еще не назвали, это тоже не удастся.
Если определенные свойства необходимы сущности, выполняющей свою работу, они могут быть инициализированы в конструкторе. Другой подход - иметь логическое значение, которое проверяет, находится ли объект в состоянии, в котором может быть вызван данный метод:
while (person.hasAnotherQuestion()) {
person.answerNextQuestion();
}
Хорошее правило проектирования - убедиться, что все конструкторы инициализируют объекты в допустимые состояния и что все установщики свойств и методы затем обеспечивают правильное состояние. Таким образом никогда не будет никаких объектов в недопустимом состоянии.
Если значения по умолчанию для A
и B
, которые равны 0, не являются допустимым состоянием, которое дает допустимый результат из GetComplexResult
, вы должны создать конструктор который инициализировал A
и B
для проверки состояния.
Если некоторые поля никогда не могут быть пустыми, вы обычно делаете их параметрами для конструктора класса. Если у вас не всегда доступны все требуемые значения одновременно, может оказаться полезным использование класса построителя.
Например:
public Builder {
private int a;
private int b;
public Class1 create() {
// some validation logic goes here
// to make sure we have everything and
// either fill in defaults or throw an error
// if needed
return new Class1(a, b)
}
public Builder a(int val) { a = val; }
public Builder b(int val) { b = val; }
}
Этот Строитель затем можно использовать следующим образом.
Class1 obj1 = new Builder().a(5).b(6).create();
Builder builder = new Builder();
// do stuff to find value of a
builder.a(valueOfA);
// do stuff to find value of b
builder.b(valueOfB);
// do more stuff
Class1 obj2 = builder.create();
Class2 obj3 = builder.create();
Этот дизайн позволяет вам заблокировать классы Entity в любой степени, в которой это необходимо, при этом обеспечивая гибкий процесс построения. Это также открывает дверь для настройки процесса построения с другими реализациями без изменения контракта класса сущности.