簡體   English   中英

如何實現工廠設計模式

[英]How to implement factory design pattern

我正在嘗試將工廠設計模式應用於應用程序中的實際問題。 我正在使用數據對象(有點像ORM,但不完全是),其中一個對象代表數據庫中的一行,其屬性為列。 話雖如此-我有3種不同類型的用戶,它們都擴展了基類User ,並且都保存在同一users數據庫表中。 我還有一個用於確定用戶type的額外列type

因此,要獲取ID為1的用戶,我將使用以下代碼:

$user = User::getByPK(1);

但是,不同類型的用戶具有不同的屬性和方法,我需要獲取適當的實例,這就是我遇到的問題。 我創建了一個工廠類,但是我不確定如何調用它。 在確定用戶類型之前,我需要從數據庫中獲取有關該用戶的信息,但是我需要實例化適當的類,並且這兩件事相互依賴。

這就是我所做的-我得到了適當的實例,但有關用戶的所有信息都保留在基類中。

class UserFactory {

    public function getUser($type) {

        switch($type) {
            case User::ORDINARY:
                return new OrdinaryUser();

            case User::MODERATOR:
                return new Moderator();

            case User::ADMINISTRATOR:
                return new Administrator();
        }
    }
}


$user = User::getByPK(1); // Has all the information

$factory = new UserFactory();

$object = $factory->getUser($user->type); // Is instance of Administrator

在這種情況下,使用工廠模式的正確方法是什么?

工廠模式的思想是從對象本身分離和封裝創建對象實例所需的邏輯。 這將關注點分開。

當前,您的User類上有一個靜態方法,該方法負責從數據庫中獲取用戶信息。 這會將您的User對象耦合到您的數據庫。 它也很僵化。

  • 如果您的用戶存儲在其他類型的數據庫中怎么辦?
  • 如果您的用戶存儲在XML文件中怎么辦?
  • 如果您的用戶存儲在鍵/值存儲中怎么辦?
  • 如果要創建用於編寫測試的用戶模擬存儲庫怎么辦?

工廠模式使您可以將這些問題抽象化,並根據需要提供工廠的替代實現(假設每個實現都有一個通用的接口)。 也許創建用戶的方式會發生變化,但是您也不想在創建用戶所需的任何地方也進​​行更改-而是如何創建用戶。 將此代碼隔離到工廠中即可。

如果您已經抽象了DAL,則工廠也可以將其作為DAL的實例。 (我將使用IDataAccessLayer作為首選DAL的占位符)

class UserFactory {
    private IDataAccessLayer $dataAccessLayer;

    public function __constructor($dataAccessLayer) {
        $this->dataAccessLayer = $dataAccessLayer;
    }

    public function createUser($userId) {
        $userDataSet = $this->dataAccessLayer->someQuery($userId);

        switch ($userDataSet->type) {
            case UserType::Administrator:
                return createAdministrator($userDataSet);
            case UserType::Moderator:
                return createModerator($userDataSet);
            case UserType::Ordinary:
                return createOrdinaryUser($userDataSet);
        }
    }

    private function createAdministrator($userDataSet) { /* Create and return an administrator */ }
    private function createModerator($userDataSet) { /* Create and return a moderator */ }
    private function createOrdinaryUser($userDataSet) { /* Create and return an ordinary user */ }
}

然后,您可以這樣使用:

$factory = new UserFactory($dataAccessLayer);
$factory->createUser(1);

(和我在一起,我已經有幾年沒有編碼PHP了,所以我的某些語法可能已經關閉,但是想法是一樣的)

現在,就個人而言,您似乎需要在這里進行更詳細的介紹。 我將按照存儲庫模式創建一個UserRepository。 我認為這是因為工廠實際上不應該訪問數據庫。 它應該只使用數據庫中的數據來創建用戶。 存儲庫模式應該負責從數據庫中獲取數據,然后將數據饋送到工廠模式以獲取對象。

class UserRepository {
    private IDataAccessLayer $dataAccessLayer;

    public function __constructor($dataAccessLayer) {
        $this->dataAccessLayer = $dataAccessLayer;
    }

    public function getUserById($id) {
        $userData = $this->dataAccessLayer->fetch(someQuery);

        $factory = new UserFactory();
        return $factory->createUser($userData);
    }
}

然后,您將擁有一個更簡單的工廠:

class UserFactory {
    public function createUser($userData) {
        switch ($userData->type) {
            case UserType::Administrator:
                return createAdministrator($userData);
            case UserType::Moderator:
                return createModerator($userData);
            case UserType::Ordinary:
                return createOrdinaryUser($userData);
        }
    }

    private function createAdministrator($userDataSet) { /* Create and return an administrator */ }
    private function createModerator($userDataSet) { /* Create and return a moderator */ }
    private function createOrdinaryUser($userDataSet) { /* Create and return an ordinary user */ }
}

從您的代碼中,您將得到類似:

$userRepository = new UserRepository($dataAccessLayer); //This is probably done somewhere higher in your code.
$userRepository->getUserById(1);

您可能需要繼續創建以下接口並也實現它們。 這將使您能夠執行合同,並設置自己以能夠根據需要交換實現。

public interface IUserRepository {
    function getUserById($userId);
}

public interface IUserFactory {
    function createUser($userData);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM