Mar*_*leu 6 php design-patterns abstract-factory
我目前有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();
}
Run Code Online (Sandbox Code Playgroud)
这是我的第一个用例:创建一个新的管理员.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我创建了一个新的抽象类,因为我的两个用例属于同一个实体(Salesman和Managers都是具有不同访问级别的Staff).
abstract class StaffRecord extends UserFactory {
protected $staffController;
function __construct() {
parent::__construct();
$this->staffController = new staffController();
}
}
Run Code Online (Sandbox Code Playgroud)
这里,SignUp的签名与Admin相同,后者排除使用func_num_args()和func_get_args().等等,但在Java中,您将无法使用Method Overload来解决此问题.没错,但在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);
}
}
Run Code Online (Sandbox Code Playgroud)
这里的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);
}
}
Run Code Online (Sandbox Code Playgroud)
这里的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);
}
}
Run Code Online (Sandbox Code Playgroud)
我认为你没有抓住工厂的重点。从工厂生成的类不会扩展工厂,工厂会生成适当的类或子类的对象实例。您可以扩展一个工厂来创建一个更具体的工厂,但这是一个不同的主题。
、等.. 应该扩展一个公共抽象AdminRecord基类,而不是. 工厂只是建立相应的用户记录。ManagerRecordUserRecordUserRecordFactory
绕过不同签名的最简单方法是传入包含所需属性的选项对象或数组。下面我展示了该数组,但您可能需要一个UserSignupConfig可以扩展用于特定用途的类,例如AdminSignupConfig并传入而不是通用数组。
abstract class UserRecord {
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(array $config = array());
//or via optional object of type UserSignupConfig
// "abstract public function signUp(UserSignupConfig $config = null);"
Run Code Online (Sandbox Code Playgroud)
}
在最基本的示例中,TheUserRecordFactory可以有一个构建器方法来构造UserRecords(或任何子类)。
//Create the factory
$userRecordFactory = new UserRecordFactory();
//Grab me something that extends UserRecord
$adminRecord = $userRecordFactory->churnOutUserRecord("AdminRecord");
Run Code Online (Sandbox Code Playgroud)
该churnOutUserRecord方法可以是一个简单的开关:
public function churnOutUserRecord($type){
$record = null;
switch($type){
case "AdminRecord": $record = new AdminRecord(); break;
case "ManagerRecord": $record = new ManagerRecord(); break;
///...
}
return $record;
// ...Or just "return new $type;"
// if you are 100% sure all $types are valid classes
}
Run Code Online (Sandbox Code Playgroud)
最后一点:所有这些抽象类的使用并不是我喜欢的次要代码重用的方式。相反,我建议尽可能使用接口,但这是一个更深层次的主题。