2012-08-27 7 views
1

我是OOP的新手,並且認爲我會給Silex嘗試一個我嘗試的小應用程序。我正在尋找一些建議,以確定我的設計是否符合良好的面向對象的原則。使用數據庫驅動的應用程序示例在面向對象的理論和實踐之間建立聯繫

我有一個User對象,它基本上只是一堆屬性,getters和setter。然後我有一個UserService對象,其中將包含驗證用戶,從數據庫獲取用戶,設置或更新用戶信息等的邏輯。我還有一個UserServiceProvder類,該類用於嚮應用程序提供UserService類的實例(這似乎是在Silex中創建可重用代碼塊的最佳方式)。

我現在的問題是這樣的:我使用Silex附帶的Doctrine DBAL,當我實例化UserService類時,我試圖傳入對Doctrine對象的引用,然後對該對象進行硬編碼調用反對到UserService類的方法。

例如,通過ID從數據庫返回User,我可能會創建一個名爲getUserById($id)方法,然後硬編碼原則編制聲明成的方法來從數據庫中選擇該用戶,然後返回一個User對象。

對我來說創建一個完整的其他服務只是對Doctrine DBAL的進一步抽象,並在我實例化時將其傳遞給UserService會更好嗎?這樣一來,我就可以將準備好的陳述硬編碼到該類中,從而使我的類更加封裝並且可重用,以防將來決定不再使用教義。

我想我很難與正在意識到如果有這樣的事情在面向對象過度殺傷。在我看來,第二種方法更具可重用性,但它有必要還是明智?

回答

5

將數據庫訪問權移動到單獨的類會帶來一些優勢。首先,如果您將數據庫訪問與其他邏輯分開,則可以更輕鬆地替換數據庫訪問的實現。如果出於某種原因想要放棄Doctrine DBAL,您會很高興所有的代碼都只是引用某個存儲庫接口,而不是直接查詢數據庫。

第二大優勢是您可以在分離數據庫訪問邏輯時測試您的應用程序邏輯。如果您爲UserService內的用戶注入一個Repository,則可以在測試中對此進行模擬,並確保只有在實際應用邏輯出現問題時纔會失敗。

的你可以做什麼

接口一個小例子是便於在整個代碼庫的參考。沒有代碼引用實現,只有接口。這樣,你可以很容易地更換接口的實現不接觸它使用的所有地方:

interface IUserRepository 
{ 
    /** 
    * @return User 
    */ 
    public function getUserById($userId); 
} 

當然,你需要的實現所述接口。這是你注入你的UserService的內容。這是你有一天可能會用接口的另一個實現替換:

class DoctrineDBALUserRepository implements IUserRepository 
{ 
    /** 
    * @return User 
    */ 
    public function getUserById($userId) 
    { 
    //implementation specific for Doctrine DBAL 
    } 
} 

UserService只知道接口,可以自由使用它。爲了避免必須在代碼中的很多地方注入UserRepository,您可以創建一個便捷的構建方法。請注意,引用接口並注入該接口的實施構建方法構造:在地方,你可以編寫業務邏輯測試

class UserService 
{ 
    private $UserRepository; 

    public static build() 
    { 
    return new UserService(new DoctrineDBALUserRepository()); 
    } 

    public function __construct(IUserRepository $UserRepository) 
    { 
    $this->UserRepository = $UserRepository; 
    } 

    public function getUserById($userId) 
    { 
    if ($User = $this->UserRepository->getUserById($userId) { 
     return $User; 
    } 
    throw new RuntimeException('O noes, we messed up'); 
} 

有了這個(例如,如果無法保存,將拋出一個異常):

public function UserServiceTest extends PHPUnit_Framework_TestCase 
{ 
    public function testGetUserById_whenRetrievingFails_shouldThrowAnException() 
    { 
    $RepositoryStub = $this->getMock('IUserRepository'); 
    $RepositoryStub->expects($this->any())->method('getUserById')->will($this->returnValue(false); 

    $UserService = new UserService($RepositoryStub); 
    $this->setExpectedException('RuntimeException'); 
    $UserService->getUserById(1); 
    } 
} 

我可以想象如果你還沒有進入單元測試,你對代碼的最後一點不熟悉。我希望你是,如果不敦促你也讀一下:D我認爲無論如何,答案的完整性都包括它是有益的。

+0

哇,謝謝!我還沒有進入測試階段,但我已經閱讀了很多,並意識到這是我需要做的。 – itsmequinn

相關問題