vendredi 23 janvier 2015

AbstractFactory in PHP without Method Overload

The Situation


I currently have 4 types of users and we predict at least 3 more in the future. For now they are:



  • Administrator (Group of shop Administrator)

  • Staff (Shop Manager)

  • Staff (Shop Salesman)

  • Customer


In a near future, I'll have to allow both staff to be also customer simultaneously. I'll also have support center and reporter.


The Problem


Creation. Creation. Creation. I'm not worried about Access Control, Permission, etc... The code I have now can do wonders in this area. My problem is only about creation. And it seems that Abstract Factory might be the one for me, but the truth is all those "abstract tutorials" teaching Design Pattern using books and cars is just not helping me bring it to my situation. Either I'm at the wrong Design Pattern or I'm not understanding it.


My Attempt


At the UserFactory class we can see the source of my problem: abstract public function signUp();. It is bad practice and even causes Strict Standard error on PHP 5.4+ to not respect a method signature. In Java, I would have method overload to solve this issue. In PHP, method overload works differently and won't allow me to work this way.



<?php

abstract class UserFactory {

const ADMIN = 'AdminRecord';
const MANAGER = 'ManagerRecord';
const SALESMAN = 'SalesmanRecord';
const CUSTOMER = 'CustomerRecord';

public static function manufacture($type) {
return new $type;
}

protected $accountController;
protected $emailController;
protected $toolMailer;

function __construct() {
$this->accountController = new AccountController();
$this->emailController = new EmailController();
$this->toolMailer = new ToolMailer();
}

abstract public function signUp();
}


Here is my first use-case: creating a new administrator.



class AdminRecord extends UserFactory {

protected $accountCompanyController;

function __construct() {
parent::__construct();
$this->accountCompanyController = new AccountCompanyController();
}

public function signUp($name, $email, $password, $companyId, $access) {
$accountId = $this->accountController->add($name, $password);
$this->emailController->add($email, $accountId);
$this->accountCompanyController->add($accountId, $companyId, $access);

$this->toolMailer->adminWelcome($name, $email, $password);
}

}


Here I create a new abstract class because two of my use-case belongs to the same entity (Salesman and Managers are both Staff with different access level).



abstract class StaffRecord extends UserFactory {

protected $staffController;

function __construct() {
parent::__construct();
$this->staffController = new staffController();
}

}


Here, the signature of the SignUp would be the same as the Admin, which rules out working with func_num_args() and func_get_args(). Wait, but in Java you wouldn't be able to use Method Overload to solve this. True, but in Java I could replace int $shopId with Shop shop and int $companyId with Company company.



class ManagerRecord extends StaffRecord {

public function signUp($name, $email, $password, $shopId, $access) {
$accountId = $this->accountController->add($name, $password);
$this->emailController->add($email, $accountId);
$this->staffController->add($accountId, $shopId, $access);
$this->toolMailer->managerWelcome($name, $email, $password);
}

}


Here the SignUp method is different from both cases seen before.



class SalesmanRecord extends StaffRecord {

public function signUp($name, $email, $password, $cpf, $shopId, $access) {
$accountId = $this->accountController->addSeller($name, $password, $cpf);
$this->emailController->add($email, $accountId);
$this->staffController->add($accountId, $shopId, $access);
$this->toolMailer->salesmanWelcome($name, $email, $password);
}

}


Here the SignUp method is even more different than before.



class CustomerRecord extends UserFactory {

protected $customerController;

function __construct() {
parent::__construct();
$this->customerController = customerController();
}

public function signUp($name, $email, $password, $cpf, $phone, $birthday, $gender) {
$accountId = $this->accountController->addCustomer($name, $password, $cpf, $phone, $birthday, $gender);
$this->emailController->add($email, $accountId);
$this->toolMailer->customerWelcome($name, $email, $password);
}

}

Aucun commentaire:

Enregistrer un commentaire