Шаблон проектирования Простая фабрика

Описание шаблона проектирования Простая фабрика с примером на PHP

Описание шаблона Простая фабрика

Основное назначение шаблона простая фабрика — отделить код по созданию объектов от прикладного кода, который эти объекты использует. Почему это выгодно, рассмотрим после примера. Такое изложение позволит более наглядно показать преимущества шаблона.

Пример шаблона Простая фабрика

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

abstract class User 
{
  protected $login;

  public __constructor($login)
  {
    return $this->login = $login;
  }

  public function getLogin()
  {
    return $this->login;
  }

  public function readAccess()
  {
    return true;
  }

  public function updateAccess()
  {
    return false;
  }

  public function writeAccess()
  {
    return false;
  }
}

Теперь в наследниках созданного класса будем изменять привилегии базового пользователя. Создадим классы, описывающие привилегии гостя и администратора.

Class GuestUser extends User
{
   // у гостя минимальные привилегии
}

Class AdminUser extends User 
{
  public function updateAccess()
  {
    return true;
  }

  public function writeAccess()
  {
    return true;
  }
}

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

Class UserFactory
{
  private static $users = array("login1"=>"guest", "login2"=>"admin",);

  public static function createUser($login)
  {
    $accessType = self::$users[$login];
    if (is_null($accessType)) {
      $accessType = "unknown";
    }
    switch($accessType) {
      case "unknown": 
	console.log("Пользователь $accessType не найден, у вас права гостя");
      case "guest": 
	return new GuestUser($accessType);
	break;
      case "admin": 
	$user = new AdminUser($accessType);
	break;
    }
    return $user;
}

Итак, мы создали классы, описывающие привилегии пользователей, затем был создан класс, метод которого в зависимости от входного параметра создает объект одного из классов привилегий. Кто-то может спросить, зачем создавать класс UserFactory, если объекты можно создать оператором new? Отвечу, как в Одессе, вопросом на вопрос. А если нам придется изменить систему привилегий, а у нас такие объекты создаются достаточно часто? Что будет проще в итоге: один раз потрудиться в начале над классом фабрики UserFactory, или потеть потом в поисках операторов new в исходном коде? Учтите, пример с пользователями взят для наглядности, это может быть любой объект, от краски для волос до списка запчастей ракеты, а у них вероятность изменений будет повыше. Статическая переменная класса фабрики при этом скорее всего потребует другой инициализации. Например, через базу данных или вообще можно воспользоваться внешней переменной.

Пойдем дальше. Учитывая вышесказанное посмотрим, что надо будет сделать, чтобы добавить пользователя с новыми привилегиями. А заодно наглядно будут видны недостатки шаблона проектирования Простая фабрика.

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

Class EditorUser extends User
{
   public function updateAccess()
   {
      return true;
   }
}

Во-вторых, надо доработать класс фабрики объектов.

Class UserFactory()
{
  private static $users = array("login1"=>"guest", "login2"=>"admin", "login3"=>"editor",);

  public static function createUser($login)
  {
    $accessType = self::$users[$login];
    if (is_null($accessType)) {
      $accessType = "unknown";
    }
    switch($accessType) {
      case "unknown": 
	console.log("Запрошенный тип пользователя не найден, у вас будут права гостя");
      case "guest": 
	return new GuestUser($accessType);
	break;
      case "admin":
	$user = new AdminUser($accessType);
	break;
      case "editor":
	$user = new EditorUser($accessType);
	break;
    }
    return $user;
}

Сколько нам потребуется времени на такую доработку кода? Вопрос риторический.

К недостаткам шаблона относят необходимость доработки класса фабрики объектов UserFactory, а преимущество в том, что доработка используемых классов или введение новых производится в одном месте и мало влияет на код приложения.

Надеюсь, шаблон простая фабрика ясен. Полезен он или нет в каждом конкретном случае, решать вам.