Рефакторинг: встраивание класса

Представим себе такую ситуацию, когда мы провели серию приемов рефакторинга и в результате оказалось, что от класса становится мало пользы, т.к. в нем осталось мало функций. Проблема, которая может быть решена с помощью сегодняшнего приема, - это устранение малого класса. Хотя это, конечно, не проблема. Но все же :)

Суть приема встраивания класса состоит в том, чтобы встроить имеющиеся функции нашего класса А в другой класс Б, который чаще всего использует функции класса А. Сам класс А при этом удалить.

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

Допустим у нас есть два класса - Person и PhoneNumber. При этом класс Person использует методы класса PhoneNumber:

class Person {
	private $_name;
	private $_officePhone;
	public function __construct() {
		$this->_officePhone = new PhoneNumber();
	}
	public function GetName() {
		return $this->_name;
	}
	public function GetPhoneNumber() {
		return $this->_officePhone->GetPhoneNumber();
	}
	public function GetOfficePhone() {
		return $this->_officePhone;
	}
}
class PhoneNumber {
	private $_number;
	private $_areaCode;
	public function GetPhoneNumber() {
		return '('.$this->_areaCode.') '.$this->_number;
	}
	public function GetAreaCode() {
		return $this->_areaCode;
	}
	public function SetAreaCode($arg) {
		$this->_areaCode = $arg;
	}
	public function GetNumber() {
		return $this->_number;
	}
	public function SetNumber($arg) {
		$this->_number = $arg;
	}
}

Чтобы применить наш прием, сначала нужно добавить в класс Person методы из класса PhoneNumber:

class Person {
	…
	public function GetAreaCode() {
		return $this->_officePhone->GetAreaCode();
	}
	public function SetAreaCode($arg) {
		$this->_officePhone->SetAreaCode($arg);
	}
	public function GetNumber() {
		return $this->_officePhone->GetNumber();
	}
	public function SetNumber($arg) {
		$this->_officePhone->SetNumber($arg);
	}
	…
}

После этого шага мы можем использовать код

$myPerson = new Person();
$myPerson->setAreaCode ("123");

вместо кода, который мы использовали бы раньше:

$myPerson = new Person();
$myPerson->getOfficePhone()->setAreaCode("123");

Таким образом, мы избавляемся от создания лишнего объекта (который на самом деле пока создается внутри класса Person).

А после этого шага мы можем спокойно применять такие приемы рефакторинга, как «Перемещение метода» и «Перемещение поля», о которых я расскажу в следующих постах.

Но и без их описания не трудно догадаться, что мы теперь можем выкинуть метод GetOfficePhone из класса Person, и можем переместить тела методов GetPhoneNumber, GetAreaCode, SetAreaCode, GetNumber, SetNumber. Но перед этим конечно нужно переместить внутренние поля _number и _areaCode класса PhoneNumber в класс Person. А затем мы можем смело удалить класс PhoneNumber, инициализацию поля _officePhone в классе Person и само поле _officePhone в классе Person.

В результате применения этих приемов класс PhoneNumber исчезнет совсем, чего мы и добивались, а класс Person станет таким:

class Person {
	private $_name;
	private $_number;
	private $_areaCode;
	public function GetName() {
		return $this->_name;
	}
	public function GetPhoneNumber() {
		return '('.$this->_areaCode.') '.$this->_number;
	}
	public function GetAreaCode() {
		return $this->_areaCode;
	}
	public function SetAreaCode($arg) {
		$this->_areaCode = $arg;
	}
	public function GetNumber() {
		return $this->_number;
	}
	public function SetNumber($arg) {
		$this->_number = $arg;
	}
}

Думаю, это полезный прием очищения кода, который кому-нибудь обязательно пригодится :)





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



4 Ответов на “Рефакторинг: встраивание класса”

  1. Big_Shark

    Такое может понадобиться только изночально при неправельной архитектуре проекта
    По мне так статья бесполезная(

  2. novice

    Если говорить про архитектуру, то не всегда удается с первого раза создать такую архитектуру, которая была бы идеальна для конкретного проекта. А то, что статья бесполезная - это Ваше субъективное мнение.

  3. У класса Person метод setAreaCode не совсем понятен. Если же # $myPerson->getOfficePhone()->setAreaCode(“123″) вот так делаем, то понимаем, что устанавливаем код для телефона. Каждый класс и объект этого классы занимается теми вещами, которые ему присущи. Смотрите антипаттерн - Божественный объект.

  4. Игорь

    Нормальная статья. Насчет правильной архитектуры, построить такую сразу не реально, поэтому и есть реффакторинг.


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