问题
I have the following code:
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();
}
}
}
The problem is that ServiceB depends on some results from ServiceA. My idea is to create container class for storing the results, then inject it into both ServiceA and ServiceB:
class ServiceResults
{
public string SomeProperty {get; set;}
}
public ServiceComposite()
{
ServiceResults result = new ServiceResults();
_services.Add(new ServiceA(result));
_services.Add(new ServiceB(result));
}
I am wondering if it is the best possible way to solve the problem. Maybe it breaks some principles or rules of which I don't know, or is simply "code smell". What are the better ways to do this?
回答1:
If ServiceB
needs ServiceA
's result for it to function properly then why not have ServiceB
depending on 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; }
}
Then in the case that you execute all Service
s in a collection you can add a ServiceBase
to make sure this service executes only once: (Full example)
On this basic implementation you can add: Async Execute
, Thread-safe checking of the executing of InnerExecute
, Flyweight factory for the generation of the specific IService
, Have a ResponseBase
with derived responses for each 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; }
}
And whoever uses these 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; }
}
Probably you will want to access the factory by some mapping key and probably you will want proper logic in the SomeOtherThatExecuteServices
but all this will put you on the right way (+Using some proper IoC Container)
来源:https://stackoverflow.com/questions/38481859/composite-design-pattern-how-to-pass-results-from-one-component-into-another