2016-07-22 81 views
2

我對這個神祕的標題感到非常抱歉,但我真的不知道如何用簡短的標題風格來形容它。PHP:如何在不違反SOLID原則的情況下使用擴展接口?

首個簡短版本。簡單的郵件確認機制。一種方法是發送帶確認鏈接的電子郵件。點擊鏈接後,另一個控制器調用第二個方法,該方法從URL中驗證令牌。在兩個動作之間ConfirmationObject正在被存儲,包括令牌和其他可能的數據。成功確認使用「successHandler」後。

簡化代碼:

interface SuccessHandlerInterface { 
    public function success(ConfirmationObjectInterface $object); 
} 

class EmailTester { 
    public function try(ConfirmationObjectInterface $object) { 
     // some code 
    } 

    public function confirm($token) { 
     $confirmationObject = $this->repository->findByToken($token); 

     $type = $confirmationObject->getType(); 
     $successHandler = $this->handlersRegistry->getSuccessHandler($type); 
     $successHandler->success($confirmationObject); 
    } 
} 

現在,我們將使用這種方式:

// Firstly let's implement our own success handler. 
class UserRegistrationSuccessHandler implements SuccessHandlerInterface { 
    public function success(ConfirmationObjectInterface $object) { 
     // Do some stuff on success. 
    } 
} 

// Then let's register this success handler to be available in our `handlersRegistry` object. 
$handlersRegistry->addType('user_registration', new UserRegistrationSuccessHandler()); 

// Now we will extend ConfirmationObjectInterface 
interface RegistrationConfirmationObjectInterface extends ConfirmationObjectInterface { 
    public function getSomeDataGivenOnRegistration(); 
} 

// And at the end, let's try our email 

$confirmationObject = new RegistrationConfirmationObject(); // Which implements above interface. 
// $confirmationObject->getType() === 'user_registration' 

$emailTester->try($confirmationObject); 

// Now confirmation link with token is being sent to the given email. If user will click it, below method will be invoked. 
$emailTester->confirm($token); 

現在的問題是,我寧願希望有RegistrationConfirmationObjectInterface中可用的成功處理程序,而比ConfirmationObjectInterface

我知道我可以做:

// Firstly let's implement our own success handler. 
class SuccessHandler implements SuccessHandlerInterface { 
    public function success(ConfirmationObjectInterface $object) { 
     if ($object instanceof RegistrationConfirmationObjectInterface) { 
      // Do stuff 
     } 
    } 
} 

但感覺不好。此檢查是毫無意義的,因爲$object將始終是RegistrationConfirmationObjectInterface的一個實例。這種設計有何缺陷,以及如何改進?

+0

我可能會在這裏得到錯誤的結尾,但是你沒有實例化接口,所以這種事情對我來說沒什麼意義:'公共函數成功(ConfirmationObjectInterface $ object)'< - 是一個接口或對象(類實例)? – CD001

+0

@ CD001它強制傳遞的對象來實現接口,否則php會拋出一個錯誤。 –

+0

@FélixGagnon-Grenier確實有效嗎? – CD001

回答

0

我不清楚爲什麼確認對象應該實現兩個接口。從我在這裏看到的RegistrationConfirmationObjectInterface只有一個方法返回一些數據結構,並且ConfirmationObjectInterface根本沒有方法。在這裏,嚴格的型號安全是非常必要的,特別是如果您確定您的定製SuccessHandler在任何時候都會收到RegistrationConfirmationObjectInterface

如果ConfirmationObjectInterface實現不包含邏輯並且只是數據結構,請將其替換爲關聯數組。否則,我建議是這樣的:

interface ConfirmationObjectInterface 
{ 
    /** 
    * @return array 
    */ 
    public function getData(); 
} 

class RegistrationConfirmationObject implements ConfirmationObjectInterface 
{ 
    public function getData() 
    { 
     return ['data specific to registration here']; 
    } 
} 

class SomethingElseConfirmationObject implements ConfirmationObjectInterface 
{ 
    public function getData() 
    { 
     return ['data specific to something else']; 
    } 
} 

由於自定義處理程序是針對具體的類型,他們會知道什麼樣的數據,從getData()期待呢。

+0

這是簡化的代碼。 'ConfirmationObjectInterface'實際上有自己的方法,例如「getType」,「getEmail」或「getToken」。我當前的實現實際上取決於關聯數組,因爲我無法更好地解決這個問題,但我開始懷疑是否真的沒有其他方法:)。 –

+0

這是什麼意思,「更好」?超嚴格型安全並不總是更好。如果'ConfirmationObjectInterface'中的所有方法都是getter,那麼這些對象實際上就是數據結構,並不一定是接口。接口的目的是從「what」抽象出「how」,爲最簡單的東西創建額外的接口只會增加複雜性,並不能解決任何實際問題。 –

+0

這是一個很好的觀點。我把這個特定的項目變成了一個練習,將界面推到極限,看看他們什麼時候停止有意義 - 以提高我對它們的理解。我會考慮你的答案,如果它是正確的,那麼我會完全接受它:)。 –

相關問題