2013-03-13 58 views
1

我寫了下面的類關於DI和SRP

public class UserApplication 
{ 
    private IUserRepository UserRepository { get; set; } 

    private IUserEmailerService UserEmailerService { get; set; } 

    public UserApplication(IUserRepository userRepository, IUserEmailerService userEmailerService) 
    { 
     this.UserRepository = userRepository; 
     this.UserEmailerService = userEmailerService; 
    } 

    public bool Authenticate(string login, string pass) 
    { 
     // Here I use UserRepository Dependency 
    } 

    public bool ResetPassword(string login, string email) 
    { 
     // Here I only use both Dependecies 
    } 

    public string GetRemeberText(string login, string email) 
    { 
     // Here I only use UserRepository Dependency 
    } 
} 

我使用統一的管理我的實例,使我意識到,當我問的容器,我只用在只有一個方法,這樣既依賴給這個類的一個實例,兩個依賴項都被注入到這個類中,但我不需要這兩個實例,所以在Authenticate用戶中我只需要存儲庫。 所以我錯了嗎?有沒有另一種方法,只有我在這堂課的所有案例中使用依賴性?

我想到用命令模式到,所以我班3班有一個方法,只有依賴我需要裏面,像這樣:

public class AuthenticateUserCommand : ICommand 
{ 
    private IUserRepository UserRepository { get; set; } 

    public string Login { get; set; } 

    public string Password { get; set; } 

    public void Execute() 
    { 
     // executes the steps to do that 
    } 
} 



public class ResetUserPasswordCommand : ICommand 
{ 
    private IUserRepository UserRepository { get; set; } 

    private IUserEmailerService UserEmailerService { get; set; } 

    public string Login { get; set; } 

    public string Email { get; set; } 

    public void Execute() 
    { 
     // executes the steps to do that 
    } 
} 
+1

對於ASP.NET MVC,由於控制器的性質,我可以看到第一個示例更可取,後一個示例可以很好地適用於WPF MVVM,因爲您可以直接綁定您的命令。這實際上取決於你使用的是什麼技術。 – Romoku 2013-03-13 02:34:52

+0

沒有這個類是ASPNET MVC的一部分,這是我係統的一個層。 – Greg 2013-03-13 03:55:48

+0

當一個類被注入一個不主要由那個類使用的依賴時,這可能意味着這個類可能做了它不負責的事情,從而打破了可能不是你的情況的SRP原則,我只是建議。 – 2013-03-14 01:40:25

回答

0

另一種方法是創建一個特定的角色界面每個行爲。所以你會有IUserAuthenticationService,IUserPasswordResetServiceIUserRememberPasswordService。這些接口可以由一個類來實現,比如UserApplication,或者它們可以通過單獨的類來實現,以維護SRP。您所描述的命令模式對SRP具有類似的優勢。命令模式的一個問題是這些依賴關係仍然必須由某些東西提供。如果依賴關係是由控制器提供的,那麼您仍然必須首先獲得控制器的依賴關係,並且您留下的問題與第一個示例類似。

特定於角色的界面案例以及命令模式的權衡是內聚力的喪失。這個成本無疑是一個偏好和觀點,以及您希望實施SRP的程度。一方面,通過具有單個類處理認證相關行爲而提供的內聚可能是有益的。另一方面,它可能導致依照您描述的依賴性錯位。

+0

好吧,但如果我爲每個行爲創建一個接口並在UserApplication類上實現接口,您同意我的看法,當我要求容器給我一個此類的實例時,其他兩個依賴項將注入UserApplication,所以問題仍然存在繼續。 怎麼樣讓容器給我一個實例依賴每種方法? – Greg 2013-03-13 03:53:32

+0

我真的更喜歡每個行爲都有接口,並且在一個類上實現它,但是我不太喜歡這樣做,因爲我的系統將有很多具有單一方法的類。 – Greg 2013-03-13 03:58:10

+0

是的,如果UserApplication實現所有接口,你回到你開始的地方。是的,使用特定於角色的界面方法,您將最終獲得很多類。這是權衡。你要麼有很多小型的專業課程,要麼有更大的可能的混合課程。這些是函數式編程解決的OOP陷阱的一部分。 – eulerfx 2013-03-13 03:59:39

0

我通常按照您正在考慮的方式來實現命令模式的一種形式。但是,它也包含了eulerfx提到的內容。我只是稱他們爲任務。例如:

public interface ITask 
{ 
    void Execute(); 
} 

public interface IAuthenticateTask : ITask {} 

public interface IResetPasswordTask : ITask {} 

然後我實現這些,並注入所需的依賴關係。所以我有角色特定的接口和實現。

我會不是去與服務定位器,你在你的答案位陳述。

當我遇到需要訪問各種任務的情況時,我在ASP.NET MVC項目的控制器中執行操作,我使用屬性注入而不是構造函數注入。我只有我的DI容器(我使用castle)需要在運行時根據約定進行一些注入。

通過這種方式,我仍然可以輕鬆地測試控制器,因爲我不需要提供所有構造函數注入的對象,但只需要那些我需要用於測試的屬性,並且還需要某些注入屬性正如將由構造函數注入提供的那樣。

更新:

有一對夫婦使用這種方法可用的選項。人們對任務感興趣的主界面是角色特定的界面。繼承的接口(如ITask)僅用於簡單情況下的方便。它也可以與仿製藥進行擴展:

public interface ITask<TInput> 
{ 
    void Execute(TInput input); 
} 

public interface IOutputTask<TOutput> 
{ 
    TOutput Execute(); 
} 

public interface IOutputTask<TOutput, TInput> 
{ 
    TOutput Execute(TInput input); 
} 

再一次,這些是爲了方便:

public interface IAuthenticateTask : IOutputTask<bool> {} 

// or 

public interface IAuthenticateTask : IOutputTask<AuthenticationResult> {} 

你可以只在角色級別工作:

public interface IAuthenticateTask 
{ 
    AuthenticationResult Execute(string username, string password); 
} 

一個只需要依靠依賴關係的角色特定接口。

+0

謝謝你!以及關於ideia這個簡單的類與Execute方法,然後使用UserApplication來處理呢?像這樣 public bool Authenticate(IAuthencateUserTask task){task.Execute(); } – Greg 2013-03-13 04:52:25

+0

我已經更新了答案,以說明只有在角色特定的接口上依賴(應該如此)時的某些選項。 – 2013-03-13 05:33:31

0

所以我錯了嗎?

第2號依賴不是世界末日,它們不會使構造函數變得臃腫或不可讀。

以前給出的答案很適合用於3-4 +依賴關係的情況。

如果僅在該方法中使用,您也可以偶爾將特定的依賴項作爲參數傳遞給方法。從這個意義上說,你可能想試試Unity的method call injection,儘管我不確定它是否正是爲此目的而設計的。