Skip to content

Instantly share code, notes, and snippets.

  • Save eterekhin/fd7e05f1715c803f17055952a05dcbae to your computer and use it in GitHub Desktop.
Save eterekhin/fd7e05f1715c803f17055952a05dcbae to your computer and use it in GitHub Desktop.
Fowler.Refactoring.Self Encapsulate Field.Replace Data Value With Object.Change Value To Reference.Change Reference To Value.Replace Array With Object.Duplicate Observer Data.Change Unidirectional Association to Bidirectional.Change BidirectionalAssociation to Unidirectional.

Self Encapsulate Field

public int _value; 

Побавляем и меняем модификатор доступа _int

private int _value; 
 public int Value
        {
            get
            {
                /* логика*/
                return _value;
            }
            set
            {
                /*логика*/
                _value = value;
            }
        }

Полезно, когда при изменении поля нужно что-то делать (менять еще какое-то поле) , тогда в setter можно дописать логику, или добавить кеширование в getter

Replace Data Value With Object

Противоположность 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 появляет метод конвертирования, поэтому логично вынести все в отдельный класс

Change Value To Reference

Этот прием постоен на различной иденцификации ссылочных объектов, идентификация похожа на идентификацию Value Object и Entity в DDD Есть Entity - который должен иметь идентификатор и сущность с таким идентификатором должна быть одной в системе, и Value Object, который определяется данными, которые он хранит, обычно у них переопределен GetHashCode как побитовая конъюнкция значений свойств Рефакторинг заключается в преобразовании Value Object'a к Entity, чаще всего это нужно, когда мы хотим структирировать систему и указать, что ввести дополнительную логику, которая появляется если у двух других объектов в системе есть ссылка один наш объект Также Fowler делаем акцент, что Value Object'ы должны быть неизменяемыми, т.е не должны хранить состояние, а всегда пересоздаваться, это имеет смысл, так как такие объекты всегда очень просты, и могут использоваться в многопоточных вычислениях (нет гонки потоков, когда один поток поменял значение, а другой использует старое) Также, возможна, ситуация когда теперь нам нужно принять какое-то значение в Value Object за ключ.

Рефакторинг довольно прост, находим в системе все места, где этот использовалось сравнение этих объектов, скорее всего после замены GetCode и Equals все должно быть хорошо, если возникла необходимость в таком рефакторинге

Change Reference To Value

Проблема возникает, когда ссылочный объект нужно сравнивать не по ссылке, т.е объекта равны, если у них равны какие-то поля, или комбинация полей, полезно в распределенных системах, из-за отсутсвия гонки, и при рефакторинге системы вызванном излишней сложностью, Value Object'ы должны быть неизменяемы с переопределенными методами GetHashCode и Equals Также к такому приему стоит прибегнуть, когда роль этого объекта в системе поменялась

Replace Array With Object

Основная идея - не нужно класть все данные класса в массив, если этот массив всегда будет фиксированного размера и объекты семантически не равны, например :

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}";
    }

Change Unidirectional Association to Bidirectional

Иногда нужно чтобы оба объекта имели ссылки друг на друга, например, если они оба используют методы друг друга, сам прием устарел, сейчас Entity Framework, сам разруливаем проблемы взаимных ссылок

Change BidirectionalAssociation to Unidirectional

Больше не нужна двусторонняя связь между классами

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment