Рефакторинг: перемещение поля и самоинкапсуляция
По мере разработки любой сложной системы выясняется, что необходимо переместить то или иное поле или метод в новый класс. Любое правильное проектное решение через некоторое время может оказаться неправильным.
Суть приема перемещения поля такая же, как и у приема перемещения метода – переместить поле в тот класс, в который его больше всего использует. Причем под использованием здесь подразумевается и косвенное – через методы доступа. Еще, например, есть прием выделения класса, о котором я не говорил. Это противоположный встраиванию класса прием. Так вот, при выделении класса сначала перемещаются поля, а затем – методы.
Пусть у нас есть все те же (я о них упоминал в предыдущих статьях) взаимодействующие классы 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();
}
//...
}
Позже мы можем выполнить переадресацию для клиентов методов доступа (для использования нового объекта). Прием самоинкапсуляции позволяет проделывать рефакторинг более мелкими и осторожными шагами. Это удобно, когда класс сильно переделывается.
Ноябрь 27th, 2008
Привет, у тебя вроде как не спам-блог, хотя авторского маловато (все покрывает неплохое стремление рассказать о сложно-простых вещах).
В общем, инвайт на Хабр нужен?
Если ты там будешь публиковать не кросспосты, а “сборки” из своих постов – было бы хорошо. Да и тебе выгода )