Генерация объектов: задачи и решения

Опубликовал read-php в 23.05.2012 Категория: Генерация объектов ООП

Создание объекта— это слабое место в объектно-ориентированном проектировании. В раньше мы описали принцип «кодирования на основе интерфейса, а не реализации«. Поэтому в наших классах мы будем работать с абстрактными супертипами. Это делает код более гибким, позволяя использовать объекты, экземпляры которых создаются на основе различных конкретных подклассов во время выполнения программы. Побочный эффект от такого подхода состоит в том, что создание экземпляров объектов отложено.

Вот класс, конструктору которого передается строка с именем сотрудника, для которого и создается экземпляр конкретного объекта.

abstract class Employee {

protected $name;

function _construct( $name ) {

$this->name = $name;

}

abstract function fireO;

}

class Minion extends Employee {

function fire() {
print «{$this->name}: убери со стола \n»;

class NastyBoss {

private $employees = array();

function addEmployee( $employeeName ) {

$this->employees() = new Minion( $employeeName ),-

}

function projectFails0 {

if ( couilt( $this-»employees ) > 0 ) {

$emp = array_jpop( $this->employees );

$emp->fire ();

}

}

}

$boss = new NastyBoss();

$boss->addEmployee( «Игорь» );

$boss->addEmployee( «Владимир» );

$boss->addEmployee( «Мария» );

$boss->projectFails() ;

// Выводится:

// Мария: убери со стола

Как видите, мы определяем абстрактный базовый класс Employee и реализующий его класс Minion. Получив строку с именем, метод NastyBoss:: addEmployee () создает экземпляр нового объекта типа Minion. Каждый раз, когда объект NastyBoss попадает в неприятную ситуацию (из-за вызова метода NastyBoss: .-projectFails (), т.е. провала проекта), он ищет подходящий объект типа Minion, чтобы уволить его. Создавая экземпляр объекта Minion непосредственно в классе NastyBoss, мы ограничиваем гибкость последнего. Вот если бы объект NastyBoss мог работать с любым экземпляром объекта типа Employee, мы могли бы сделать код доступным для изменения прямо во время выполнения программы, просто добавив дополнительные специализации класса Employee. Полиморфизм, показанный на рис. ниже, должен показаться вам знакомым.

Программирование PHP 00 Генерация объектов: задачи и решенияЕсли класс NastyBoss не создает экземпляр объекта Minion, то откуда он возьмется? Авторы кода обычно уклоняются от решения данной проблемы, ограничивая тип аргумента в объявлении метода, а затем с легкостью опуская демонстрацию создания экземпляров везде, за исключением тестового контекста.

class NastyBoss {

private $employees = array();

function addEmployee( Employee $employee ) {

$this-»employees() = $employee;

}

function projectFailsО {

if ( count( $this-»employees ) > 0 ) {

$emp = array_pop( $this-»employees );

$emp->fire();

}

}

}

// Новый класс типа Employee…

class CluedUp extends Employee { function fireO {

print «{$this->name}: вызови адвоката\n»;

}

}

$boss = »new NastyBoss ();

$boss->addEmployee( new Minion( «Игорь» ) );

$boss->adaEmployee( new CluedUp( «Владимир» ) );

$boss->addEmployee( new Minion( «Мария» ) );

$boss->projectFailp();

$boss->projectFailsО;

$boss->projectFails();

// Выводится:

// Мария: убери со стола

// Владимир: вызови адвоката

// Игорь: убери со стола

Хотя эта версия класса NastyBoss работает с типом Employee и поэтому получает преимущества от полиморфизма, мы все еще не определили стратегию создания объекта. Создание экземпляров объектов — это скучная работа, но ее нужно сделать.

И если здесь нужно сформулировать принцип, то такой: «делегировать создание экземпляров объекта». Мы сделали это неявно в предыдущем примере, потребовав, чтобы методу NastyBoss: : addEmployee () передавался объект типа Employee. Но мы могли бы точно так же делегировать эту функцию отдельному классу или методу, который принимает на себя ответственность генерировать объекты типа Employee. Давайте добавим статический метод к классу Employee, в котором и реализована стратегия создания объекта.

abstract class Employee {

protected $name;

private static $types = array( ‘Minion’, ‘CluedUp’, ‘WellConnected’ );

static function recruit( $name ) {

$num = rand( 1, count ( self::$types ). )-1;

$class = self::$types[$num];

return new $class( $name );

}

function _construct( $name ) {

$this->name = $namef-

}

abstract function fire();

}

// Новый класс типа Employee…

class WellConnected extends Employee { function fire() {

print «{$this->name}: позвони папику \n»;

}

}

Как видите, этому методу передается строка с именем сотрудника, которая используется для создания экземпляра конкретного подтипа Employee, выбранного случайным образом. Теперь мы можем делегировать детали создания экземпляра объекта методу recruit () класса Employee. $boss = new NastyBoss();

$boss->addEmployee( Employee::recruit( «Игорь» ) );

$boss->addEmployee( Employee::recruit( «Владимир» ) );

$boss->addEmployee( Employee::recruit( «Мария» ) );

Если вы помните, тогда мы поместили статический метод под названием getlnstance () в класс ShopProduct. Метод getlnstance () отвечал за генерацию правильного подкласса ShopProduct на основании данных, полученных в результате запроса к базе данных. Поэтому класс ShopProduct выполняет двоякую роль. Он определяет тип ShopProduct и действует как «фабрика» по созданию конкретных объектов Shop-Product.

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

Комментариев нет

Добавить комментарий