интерфейси и инжектиране на зависимости правилно използване в C#

Имам интерфейс "IUser" и клас "User", имплементиращ "IUser". Също така имам интерфейс за хранилището "IUserRepository".

Аз съм между тези два варианта:

public interface IUserRepository
{
    List<User> getAll();
    void addUser(User user);
    void alterUser(User user);
    void deleteUser(string ID);
    bool validateLogin(string session_user, string session_pass);
    User getUserByID(int ID);
    User getUserByNombre(string name);
    User getUserBySessionUser(string session_user);
}

и този

public interface IUserRepository
{
    List<IUser> getAll();
    void addUser(IUser user);
    void alterUser(IUser user);
    void deleteUser(string ID);
    bool validateLogin(string session_user, string session_pass);
    IUser getUserByID(int ID);
    IUser getUserByNombre(string name);
    IUser getUserBySessionUser(string session_user);
}

Ето моето объркване. Трябва ли моите методи в интерфейса на хранилището да връщат реални реализации или интерфейси? както можете да видите в моята първа опция връщам екземпляри „Потребител“. Какво трябва да върна, за да свържа свободно кода?

Но ако избера втория в моята реална реализация на потребителското хранилище, ще имам достъп само до методите и свойствата, които бях декларирал в моя IUser интерфейс.

например, ако извикам метод addUser от услуга, като му предам екземпляр на потребителски клас:

   myRepositoryImplementation.addUser(UserInstance);

тогава истинското ми хранилище ще хареса това

  private readonly IUser user;
  public void addUser(IUser _user)
  {
    this.user=_user;
  }

Добър валиден улов! но тогава ще имам достъп само до метода и свойствата, декларирани първоначално в интерфейса на IUser, а не до нов метод или свойство, декларирани в моя потребителски екземпляр.

също така, ако извикам метод getUserByID, ще получа екземпляр на IUser.

Така че да възобновя това

1). Това валидни подходи ли са?
2). Ако това са валидни подходи, кой трябва да използвам, за да запазя или запазя кода отделен?
3). Ако избера втория, също ако е валиден, трябва ли да декларирам в интерфейса всичко, което ще използвам по-късно? Имам предвид свойства и методи?
3). Имате ли по-добра идея?


person Rafael Córdova    schedule 05.09.2014    source източник
comment
Това може да е по-подходящо за codereview.stackexchange.com   -  person eddie_cat    schedule 05.09.2014
comment
CR.SE е за преглед на работни части от код, докато това е по-скоро въпрос за дизайн на високо ниво. Това обаче може да бъде подходящо за програмисти.SE   -  person Dan Lyons    schedule 05.09.2014
comment
Смисълът на интерфейса е да излага свойства и методи за друг код, който да използва, ако направите IUser inferface, той трябва да съдържа всички неща, от които се нуждаете.   -  person reggaeguitar    schedule 06.09.2014


Отговори (3)


1) да, и двете са валидни

3) да, свойства и методи

2) малко по-дълга история. накратко, ако имате POCO класове и сте 100% сигурни, че никога няма да кодирате срещу рамка, която не ви позволява да използвате POCO (напр. вместо това, тя настоява класовете да наследяват от специфичен за рамката базов клас), можете да отидете с първия вариант (класове).

Но не винаги работи.

Например кодиране на вашите хранилища за Linq2SQL и други хранилища за Entity Framework Code Първо, не можете да използвате същия набор от класове. Вторият (интерфейсен) подход е единственият вариант. Успешно го използвахме в няколко корпоративни приложения без проблеми.

Един съвет - ако изберете интерфейсния подход, определено се нуждаете от метод за създаване на празен екземпляр

public interface IUserRepository
{
    List<IUser> getAll();
    ...
    IUser CreateNew();
}

В противен случай клиентът на хранилището няма други средства за създаване на екземпляр от конкретен тип - типът е непознат на клиента. Някои хора обаче са склонни да преместят метода на създаване в отделен фабричен клас.

person Wiktor Zychla    schedule 05.09.2014

Определено бих се спрял на първия вариант. Наличието на интерфейс за клас на услуга като хранилище е полезно, но за клас на обект като потребител, не толкова.

Както казахте, всеки път, когато добавите свойство, ще трябва да добавите свойството и към интерфейса, което е досадно. И ако приемем, че вашият потребителски клас е прост клас без зависимости към други класове, той може лесно да се тества дори без интерфейс.

Свързано четене:

http://lostechies.com/jamesgregory/2009/05/09/entity-interface-anti-pattern/

Интерфейсите на обекти са анти-модел -- блог на Джеймс Грегъри

Трябва ли обектите да прилагат интерфейси?

person Meta-Knight    schedule 05.09.2014

Мисля, че част от вашето объркване е, че имате методи във вашия потребителски клас. Обикновено този тип моделни класове представляват само данни и не описват поведение. Така че, ако преместите методите си на по-подходящо място, цялото ви объркване ще изчезне, защото няма да има причина за интерфейс.

С други думи, преместете методите извън потребителския клас и накарайте вашето репо да работи като:

List<User> getAll();
person clhereistian    schedule 05.09.2014