PHP中的AbstractFactory没有方法重载

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 $companyIdCompany 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)

Ray*_*Ray 2

我认为你没有抓住工厂的重点。从工厂生成的类不会扩展工厂,工厂会生成适当的类或子类的对象实例。您可以扩展一个工厂来创建一个更具体的工厂,但这是一个不同的主题。

、等.. 应该扩展一个公共抽象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)

最后一点:所有这些抽象类的使用并不是我喜欢的次要代码重用的方式。相反,我建议尽可能使用接口,但这是一个更深层次的主题。