пятница, 26 декабря 2008 г.

Доменные объекты - это такие объекты, которые выражают в программе сущности из предметной области. Например, "сотрудник", "заказ", "рабочая группа", "здание", доменные объекты могут быть и более абстрактными - "тип материала", "единица измерения". Программисты, используя парадигму ООП (объектно-ориентированного программирования), стараются сводить написание кода к таким вот доменным объектам, абстрагируясь от более подробного уровня детализации, обусловленного самим языком. Доменные объекты могут обслуживаться обычными объектами, т.е. не имеющими представления в предметной области, но необходимыми для реализации программы, такими объектами могут быть, например, адаптеры базы данных.

Поскольку доменные объекты надо где-то хранить, они обычно представлены в системе в двух разных формах: программной в виде рабочего объекта, обладающего как атрибутами, так и методами, и фиксированной форме, т.е. такой, которая удобна для хранения и содержит всю необходимю информацию для восстановления объекта в том состоянии, в котором он был сохранён. Под состоянием подразумевается вся совокупность атрибутов объекта. Как правило, объекты хранятся в базе данных, но в роли хранилища может выступать и файл какого-нибудь формата.

По причине того, что формы существования объекта отличаются, программисту необходимо иметь инструменты для их двустороннего преобразования: из программной формы в фиксированную и обратно. Одним из механизмов такого преобразования является ORM (object relational mapping - "объектно-ориентированная проекция"), т.е. такая структура объектов, которая позволяет программисту абстрагироваться и от базы данных тоже. С точки зрения программы, объекты всегда остаются объектами.

Доменный объект хранит какие-то атрибуты, определяемые его классом. Эти атрибуты могут быть типизированы, хранить информацию о том, как их надо извлекать из внешнего хранилища и т.п. В плохих реализациях ORM информация об атрибуте "таскается" вместе со значением атрибута (описание и значение сливается в один объект во время инстанцирования). Это неблаготворно сказывается на объёме занимаемой оперативной памяти, потому что информация об атрибуте может быть весьма обширной, а экземпляров объекта может быть много сотен, а то и тысяч.

К сожалению, в языке PHP очень плохо продумана работа со статическими методами (эту проблему частично обещают исправить в версии 6.0), поэтому крепить информацию об атрибутах к классу неудобно (разве что создавать гигантский ассоциативный массив у самого главного родительского класса), значительно приятнее было бы иметь карту данных (совокупность описаний атрибутов) всегда под рукой у любого экземпляра доменного объекта, но при этом не хранить её в нём.

И тут нам на помощь приходит такая вещь, как статическая переменная внутри метода. Методом владеет каждый экземпляр класса, а вот статическая переменная в нём хранится одна на весь класс. Почти тем же приёмом пользуются, когда проектируют класс по паттерну Singleton.


abstract class DomainObject {
#...
public function get_map() {
static $map;
if (! $map) {
$map = $this->config();
self::check_map($map);
}
return $map;
}

abstract protected function config();
#...
}

Потомок такого класса может выглядеть как-нибудь так:

require_once 'class.DomainObject.php';
class DomainObjectRack extends DomainObject {

protected function config() {
$map = self::create_map();
$map->add(new APrototype('id', 'ID', 'fixnum'));
$map->add(new APrototype('name', 'NAME', 'string'));
$map->add(new APrototype('is_active', 'ACTIVE', 'bool'));
return $map;
}

}

Сразу после инстанцирования экземпляра объекта DomainObjectRack, мы всегда как извне, так и изнутри можем обратиться к описанию его внутренней структуры.

class TestDomainObjectRack extends UnitTestCase {
public function test_same_map() {
$rack = new DomainObjectRack();
$other_rack = new DomainObjectRack();
$this->assertReference($rack->get_map(), $other_rack->get_map());
// это один и тот же объект, но внутри экземпляра его нет
$this->dump($rack);
// дамп объекта не покажет нам карты данных, поскольку она доступна
// только из метода
}
}

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

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