2013-04-06 4 views
1

У меня есть два класса: сервер и клиент. Серверу необходимо создать экземпляр клиента в нескольких потоках, а у Клиента есть виртуальный член, который должен предоставить пользовательскую реализацию. Мой вопрос. Если класс Client является вложенным классом класса Server, или я должен использовать интерфейс и вложение зависимостей, чтобы получить пользовательскую реализацию в классе Server. Теперь класс Client также имеет множество частных методов, которые предоставляют некоторую стандартную логику, которая не должна изменяться.Должен ли я использовать вложенный класс или контейнер IoC?

public class Server 
{ 
    public void DoWork() 
    { 
     for (var i = 0;i < 10; i++) 
     { 
      Client client = new Client(); 
      client.Process(i); 
     } 
    } 
} 

public class Client 
{ 
    private void doSomething() 
    { 
     ... 
    } 

    // Needs to be overridden and provide custom logic 
    public virtual string Process(int i) 
    { 
     return i.ToString(); 
    } 
} 

Рабочий пример:

public interface IClient 
{ 
    string Process(string message); 
} 

public abstract class Client : IClient 
{ 
    public virtual string Process(string message) 
    { 
     return message; 
    } 
} 

public class CustomClient : Client 
{ 
    public CustomClient() { } 

    public override string Process(string message) 
    { 
     return string.Format("Custom Client:{0}", message); 
    } 
} 

public class Server 
{ 
    private Func<IClient> createClient;  

    public Server() { } 

    public Server(Func<IClient> client) 
    { 
     createClient = client; 
    } 

    public void DoWork() 
    { 
     for (var i = 0; i < 10; i++) 
     { 
      IClient = client = createClient(); 
      client.Process(string.Format("Client #{0}", i)); 
     } 
    } 
} 

Test Program ... вы бы пошагово, чтобы он попал в CustomClient

class Program 
{ 
    static void Main(string[] args) 
    { 
     Func<CustomClient> factory =() => new CustomClient(); 
     var server = new Server(factory); 
     server.DoWork(); 
    } 
} 
+1

Если серверу необходимо создать клиент, я бы передал ему заводский метод для его использования. Поэтому я бы пошел на инъекцию зависимости. –

+0

Вы можете передать зависимость в (SRP), но она не должна быть интерфейсом для запуска. –

+0

Так что скажем, я использую DI. Как это работает, если класс Client должен быть более или менее абстрактным классом? У меня был бы интерфейс, позволяющий сказать IClient, а затем абстрактный класс, который наследует от IClient, который имеет свою реализацию по умолчанию. Как я уже сказал, он имеет множество частных методов, которые не будут меняться только с одним виртуальным методом. Можно ли использовать DI в подклассе абстрактного класса, который наследуется от интерфейса? – ewahner

ответ

1

Если серверу необходимо создать Client, я бы передал фабричный метод серверу для его использования. Поэтому я бы пошел на инъекцию зависимости.

Например: Вы могли бы перейти к Server конструкторе создается Func<IClient> и назначить его на закрытом поле под названием, скажем, createClient, а затем вместо

Client client = new Client(); 

использование

IClient client = createClient(); 

Таким образом, вы может полностью отделить сервер и клиент.

Я предпочитаю использовать простой делегат Func, а не полный заводский класс, поскольку он (а) более прост в использовании и (б) более слабо связан.

+0

Есть ли причина принять заводской метод или завод, а не только экземпляр? –

+0

Клиент абстрактного класса должен быть унаследован и создан на основе фабрики делегатов, так как класс сервера представляет собой конкретный класс. Я не могу создать его экземпляр, поскольку класс Client может быть реализован по-разному. – ewahner

1

Вопрос, должен ли зависимость быть введена или фиксированной имеет простой ответ - класс, обеспечивающий логику, которая является субъектом перемен, является кандидатом на ввод. С другой стороны, если вы не планируете менять логику, вы кодируете фиксированные типы, как и в большинстве базовых классов.

Что вы описываете как сценарий для DI - если вы разрешите переопределить класс клиента, то вы предполагаете, что возможны изменения. DI является одним из наиболее очевидных способов обработки зависимостей и изменений в одно и то же время.

Смежные вопросы