2016-07-20 1 views
2

J'ai le code suivant:Modèle de conception composite: comment transmettre les résultats d'un composant à un autre?

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(); 
     } 
    } 
} 

Le problème est que Serviceb dépend des résultats de ServiceA. Mon idée est de créer la classe de conteneur pour stocker les résultats, puis l'injecter dans les deux ServiceA et Serviceb:

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

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

Je me demande si elle est la meilleure façon possible de résoudre le problème. Peut-être que cela brise certains principes ou règles dont je ne sais pas, ou est simplement "odeur de code". Quelles sont les meilleures façons de le faire?

+1

Je serais intéressé d'en savoir plus sur pourquoi 'B' a besoin de résultats de' A' - il semble que si tel est le cas, il n'est pas juste de les traiter comme deux séparés implémentations. –

+0

Ou le service A peut exposer les résultats en tant que propriété et transmettre le service A en tant que dépendance pour le service B – Thangadurai

+1

Vous ne mettez pas en œuvre le modèle "Composite" ici non plus. – Servy

Répondre

1

Si ServiceB a besoin du résultat ServiceA pour qu'il fonctionne correctement alors pourquoi ne pas avoir ServiceB en fonction de 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; } 
} 

Ensuite, dans le cas où vous exécutez tous les Service s dans une collection vous pouvez ajouter un ServiceBase pour vous assurer que ce service exécute une seule fois: (Exemple complet)

Sur cette implémentation de base, vous pouvez ajouter : Async Execute, vérification thread-safe de l'exécution de InnerExecute, usine pour la génération Flyweight de la IService spécifique, ont un ResponseBase avec des réponses dérivées pour chaque 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; } 
} 

Et celui qui utilise ces 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; } 
} 

probablement vous voulez accéder à l'usine par une clé de cartographie et probablement vous voulez une logique appropriée dans le SomeOtherThatExecuteServices mais tout cela vous mettrez sur la droit chemin (+ en utilisant un conteneur IoC approprié)