[英]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
對象耦合到您的數據庫。 它也很僵化。
工廠模式使您可以將這些問題抽象化,並根據需要提供工廠的替代實現(假設每個實現都有一個通用的接口)。 也許創建用戶的方式會發生變化,但是您也不想在創建用戶所需的任何地方也進行更改-而是如何創建用戶。 將此代碼隔離到工廠中即可。
如果您已經抽象了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.