Рефакторинг: перемещение поля и самоинкапсуляция

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

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

Пусть у нас есть все те же (я о них упоминал в предыдущих статьях) взаимодействующие классы Account и AccountType:

class Account {
	//...
	private $_type; // AccountType
	private $_interestRate;
	function interestForAmount_days($amount, $days) {
		return $this->_interestRate * $amount * $days / 365;
	}
	//...
}

Теперь мы хотим переместить поле _interestRate (процентная ставка) в класс типа счета (AccountType). В классе Account существует несколько методов, которые обращаются к полю _interestRate - например, метод interestForAmount_days.

Для того чтобы перенести поле _interestRate в класс AccountType, мы должны создать в AccountType это поле и определить для него методы доступа:

class AccountType {
	//...
	private $_interestRate;
	function SetInterestRate($arg) {
		$this->_interestRate = $arg;
	}
	function GetInterestRate() {
		return $this->_interestRate;
	}
	//...
}

Теперь переадресуем методы исходного класса (Account) для использования целевого класса (AccountType) и удалим поле _interestRate из исходного класса:

class Account {
	//...
	private $_type; // AccountType
	function interestForAmount_days($amount, $days) {
		return $this->_type->GetInterestRate() * $amount * $days / 365;
	}
	//...
}

Вот мы и переместили поле в целевой класс.

Рассмотрим теперь пример с самоинкапсуляцией поля. Прием самоинкапсуляции желательно применять в том случае, когда у нас есть много методов, использующих поле _interestRate. Добавим в наш исходный класс Account методы доступа к полю:

class Account {
	//...
	private $_type; // AccountType
	private $_interestRate;
	function interestForAmount_days($amount, $days) {
		return $this->GetInterestRate() * $amount * $days / 365;
	}
	function SetInterestRate($arg) {
		$this->_interestRate = $arg;
	}
	function GetInterestRate() {
		return $this->_interestRate;
	}
	//...
}

Теперь, чтобы нам избавиться от поля, достаточно выполнить переадресацию только в методах доступа:

class Account {
	//...
	private $_type; // AccountType
	function interestForAmount_days($amount, $days) {
		return $this->GetInterestRate() * $amount * $days / 365;
	}
	function SetInterestRate($arg) {
		$this->type->SetInterestRate($arg);
	}
	function GetInterestRate() {
		return $this->type->GetInterestRate();
	}
	//...
}

Позже мы можем выполнить переадресацию для клиентов методов доступа (для использования нового объекта). Прием самоинкапсуляции позволяет проделывать рефакторинг более мелкими и осторожными шагами. Это удобно, когда класс сильно переделывается.





Читайте также:



Один ответ на “Рефакторинг: перемещение поля и самоинкапсуляция”

  1. Привет, у тебя вроде как не спам-блог, хотя авторского маловато (все покрывает неплохое стремление рассказать о сложно-простых вещах).

    В общем, инвайт на Хабр нужен? :) Если ты там будешь публиковать не кросспосты, а “сборки” из своих постов - было бы хорошо. Да и тебе выгода )


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map