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

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

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

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

Допустим у нас есть два класса – 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
    Ноябрь 18th, 2008

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

  2. novice
    Ноябрь 18th, 2008

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

  3. rusk
    Ноябрь 22nd, 2008

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

  4. Игорь
    Декабрь 16th, 2008

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

Оставить комментарий


© 2008 - 2010 i-novice.net | Все права защищены.