public int _value;
Побавляем и меняем модификатор доступа _int
private int _value;
public int Value
{
get
{
/* логика*/
return _value;
}
set
{
/*логика*/
_value = value;
}
}
Полезно, когда при изменении поля нужно что-то делать (менять еще какое-то поле) , тогда в setter можно дописать логику, или добавить кеширование в getter
Противоположность Inline Class, возникает, когда я не думаю, что вокруг каких-то данных есть логика, а она появляется, например:
public class User
{
public string Name { get; set; }
public string Surname { get; set; }
public AccountType AccountType { get; set; }
public decimal Salary { get; set; }
public void ReCalculateSalary(decimal decimalSalary)
{
if (AccountType == AccountType.Contractor)
Salary = decimalSalary * 1.2m;
}
public decimal ConvertSalaryToEuro()
{
return Salary * (7 / 6m);
}
}
Тут у класса Salary появляет метод конвертирования, поэтому логично вынести все в отдельный класс
Этот прием постоен на различной иденцификации ссылочных объектов, идентификация похожа на идентификацию Value Object и Entity в DDD Есть Entity - который должен иметь идентификатор и сущность с таким идентификатором должна быть одной в системе, и Value Object, который определяется данными, которые он хранит, обычно у них переопределен GetHashCode как побитовая конъюнкция значений свойств Рефакторинг заключается в преобразовании Value Object'a к Entity, чаще всего это нужно, когда мы хотим структирировать систему и указать, что ввести дополнительную логику, которая появляется если у двух других объектов в системе есть ссылка один наш объект Также Fowler делаем акцент, что Value Object'ы должны быть неизменяемыми, т.е не должны хранить состояние, а всегда пересоздаваться, это имеет смысл, так как такие объекты всегда очень просты, и могут использоваться в многопоточных вычислениях (нет гонки потоков, когда один поток поменял значение, а другой использует старое) Также, возможна, ситуация когда теперь нам нужно принять какое-то значение в Value Object за ключ.
Рефакторинг довольно прост, находим в системе все места, где этот использовалось сравнение этих объектов, скорее всего после замены GetCode и Equals все должно быть хорошо, если возникла необходимость в таком рефакторинге
Проблема возникает, когда ссылочный объект нужно сравнивать не по ссылке, т.е объекта равны, если у них равны какие-то поля, или комбинация полей, полезно в распределенных системах, из-за отсутсвия гонки, и при рефакторинге системы вызванном излишней сложностью, Value Object'ы должны быть неизменяемы с переопределенными методами GetHashCode и Equals Также к такому приему стоит прибегнуть, когда роль этого объекта в системе поменялась
Основная идея - не нужно класть все данные класса в массив, если этот массив всегда будет фиксированного размера и объекты семантически не равны, например :
public class User
{
public string[] Info;
public string GetInfo() => $"Name : {Info[0]}, Surname : {Info[1]}";
}
Заменяется на:
public class User
{
public string Name
{
get => Info[0];
set { }
}
public string Surname
{
get => Info[1];
set { }
}
public string[] Info;
public string GetInfo() => $"Name : {Name}, Surname : {Surname}";
}
а на следующем шаге(после замены всех методов изменения Info, на изменения полей Name и Surname на :
{
public string Name { get; set; }
public string Surname { get; set; }
public string GetInfo() => $"Name : {Name}, Surname : {Surname}";
}
Иногда нужно чтобы оба объекта имели ссылки друг на друга, например, если они оба используют методы друг друга, сам прием устарел, сейчас Entity Framework, сам разруливаем проблемы взаимных ссылок
Больше не нужна двусторонняя связь между классами