【发布时间】:2015-01-23 20:04:23
【问题描述】:
情况
我目前有 4 种类型的用户,我们预计未来至少还会增加 3 种。目前他们是:
- 管理员(店铺管理员组)
- 员工(店长)
- 员工(店员)
- 客户
在不久的将来,我必须让两名员工同时成为客户。我还会有支持中心和记者。
问题
创造。创建。创建。我不担心访问控制、权限等……我现在拥有的代码可以在这方面创造奇迹。我的问题只是关于创作。似乎抽象工厂对我来说可能是一个,但事实是所有那些使用书籍和汽车教授设计模式的“抽象教程”并没有帮助我把它带到我的情况。要么我使用了错误的设计模式,要么我不理解它。
我的尝试
在 UserFactory 类中,我们可以看到我的问题的根源:abstract public function signUp();。这是不好的做法,甚至会导致 PHP 5.4+ 上的严格标准错误不尊重方法签名。在 Java 中,我会使用方法重载来解决这个问题。在 PHP 中,方法重载的工作方式不同,并且不允许我以这种方式工作。
<?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();
}
这是我的第一个用例:创建新管理员。
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);
}
}
在这里我创建了一个新的抽象类,因为我的两个用例属于同一个实体(销售员和经理都是具有不同访问级别的员工)。
abstract class StaffRecord extends UserFactory {
protected $staffController;
function __construct() {
parent::__construct();
$this->staffController = new staffController();
}
}
在这里,SignUp 的签名与管理员的签名相同,这排除了使用func_num_args() 和func_get_args()。等等,但是在 Java 中,您将无法使用方法重载来解决这个问题。没错,但在 Java 中,我可以将 int $shopId 替换为 Shop shop,将 int $companyId 替换为 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);
}
}
这里的 SignUp 方法与之前看到的两种情况都不同。
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);
}
}
这里的 SignUp 方法比以前更不一样了。
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);
}
}
【问题讨论】:
-
您可能想查看Builder Pattern。
-
另外,我个人不会在这里使用继承。我更喜欢与角色对象有关系的用户对象(或几个角色对象以同时支持您的“员工”和“客户”用例)。
-
我在这段代码中没有看到抽象工厂范式。我看到很多继承。本质上,您应该有一个使用具体工厂的抽象工厂。至于
signUp()方法的签名问题,您可以只使用一个数组作为参数来接受多个值,然后使用array_key_exists()创建适当的变量。您甚至可以使用类型提示将传递给signUp()的参数强制为数组。
标签: php design-patterns abstract-factory