2016-07-20 13 views
2

У меня есть следующий код:Композитный дизайн: как передать результаты из одного компонента в другой?

interface IService 
{ 
    void Execute(); 
} 

class ServiceA : IService 
{ 
    public void Execute() { ... } 
} 

class ServiceB : IService 
{ 
    public void Execute() { ... } 
} 

class ServiceComposite : IService 
{ 
    List<IService> _services = new List<IService>(); 

    public ServiceComposite() 
    { 
     _services.Add(new ServiceA()); 
     _services.Add(new ServiceB()); 
    } 

    public void Execute() 
    { 
     foreach (IService service in _services) 
     { 
      service.Execute(); 
     } 
    } 
} 

Проблема заключается в том, что ServiceB зависит от некоторых результатов ServiceA. Моя идея заключается в том, чтобы создать класс контейнера для хранения результатов, а затем вводит его в обоих ServiceA и ServiceB:

class ServiceResults 
{ 
    public string SomeProperty {get; set;} 
} 

public ServiceComposite() 
{ 
    ServiceResults result = new ServiceResults(); 
    _services.Add(new ServiceA(result)); 
    _services.Add(new ServiceB(result)); 
} 

мне интересно, если это самый лучший способ решить эту проблему. Может быть, это нарушает некоторые принципы или правила, о которых я не знаю, или просто «запах кода». Каковы лучшие способы сделать это?

+1

Мне было бы интересно узнать больше о том, почему 'B' нуждается в результатах от' A' - кажется, что если это так, то неправильно рассматривать их как два отдельных реализации. –

+0

Или служба A может предоставить результаты в качестве свойства и передать услугу A в качестве зависимости для службы B – Thangadurai

+1

. На самом деле вы не реализуете шаблон «Композитный». – Servy

ответ

1

Если ServiceB нуждается в результатах ServiceA, чтобы он работал правильно, то почему бы не указать ServiceB в зависимости от ServiceA?

public interface IService 
{ 
    void Execute(); 
} 

public class ServiceA : IService 
{ 
    public void Execute() { ... } 
} 

class ServiceB : IService 
{ 
    public ServiceB(IService service) 
    { 
     Service = service; 
    } 

    public void Execute() { ... } 

    public IService Servie { get; set; } 
} 

Тогда в случае, если вы выполнить все Service с в коллекции Вы можете добавить ServiceBase, чтобы убедиться, что эта услуга выполняется только один раз: (Полный пример)

На этой базовой реализации вы можете добавить : асинхронный Execute, поточно-проверка исполнения из InnerExecute, наилегчайшем завод для производства конкретного IService, Вы ResponseBase с полученными ответами для каждого Service ....

public class ServiceResponse { } 
public interface IService 
{ 
    ServiceResponse Execute(); 
} 

public abstract class ServiceBase : IService 
{ 
    public ServiceResponse Execute() 
    { 
     if (_response == null) 
     { 
      _response = InnerExecute(); 
     } 
     return _response; 
    } 

    public abstract ServiceResponse InnerExecute(); 

    private ServiceResponse _response; 
} 

public class ServiceA : ServiceBase 
{ 
    public override ServiceResponse InnerExecute() 
    { 
     return new ServiceResponse(); 
    } 
} 

public class ServiceB : ServiceBase 
{ 
    public ServiceB(IServiceFactory serviceFactory) 
    { 
     ServiceFactory= serviceFactory; 
    } 

    public override ServiceResponse InnerExecute() 
    { 
     return ServiceFactory.GetServices(ServicesTypes.ServiceA).Execute(); 
    } 

    public IServiceFactory ServiceFactory { get; set; } 
} 

И тот, кто использует эти Service S:

public enum ServicesTypes 
{ 
    ServiceA, 
    ServiceB.... 
} 

public interface IServiceFactory 
{ 
    IEnumerable<IService> GetServices(); 

    IService GetServices(ServicesTypes servicesTypes); 
} 

public class SomeOtherThatExecuteServices 
{ 
    public SomeOtherThatExecuteServices(IServiceFactory serviceFactory) 
    { 
     ServiceFactory = serviceFactory; 
    } 

    public IEnumerable<ServiceResponse> ExecuteServices() 
    { 
     return ServiceFactory.GetServices() 
          .Select(service => service.Execute()); 
    } 

    public IServiceFactory ServiceFactory { get; set; } 
} 

Возможно, вы хотите получить доступ на завод какой-то ключ отображения и, возможно, вы хотите правильную логику в SomeOtherThatExecuteServices, но все это поставит вас на Правильный путь (+ Использование некоторого подходящего контейнера IoC)