0

虽然我在Code Review中提出了这个问题,但原始代码现在正在爬行。是的,我也是Clean Code讲座的忠实粉丝,刚刚观看了那些精彩的视频,我也看到了这个another question。这是我原来的问题。依赖注入,类需要相同类型的接口的字典是一个好主意?

我有一堂课说人。基于旅行方式中某些决定的人可以调用Horse,Camel或Ship To Travel,或者也可以让所有人(在某些情况下)去旅行。

所有的马,骆驼,船有ITransport接口,当然这个接口有Travel方法。

最初的问题是,它是一种可能性,即在我的项目的续航时间我可能会得到一些新的交通工具,例如飞机,火箭,潜艇等

,所以我不能只是简单的通过他们在构造函数ITransport船,ITransport horse .....等等,因为我的构造函数参数会不断膨胀。

所以我提出了一个解决方案(我认为)HumanFactory应该有一个事件,该事件应该在Human类的构造函数中传递。

尽管我已经以某种方式删除了我的大运输列表,但正如您所知,接口可以有很多方法。所以现在我需要在需要的基础上传递大量代表,每个代表对应一个接口方法。

我甚至试图通过创建一个Human Mapper类来解决这个问题,这个类的唯一职责是映射到正确的传输,并调用正确的事件。这工作!

现在,由于这是一个虚构的例子,在现实世界的例子中,接口的方法接受参数,那么我将如何处理它呢?

我认为我要去的方向是创建维护梦魇。

我正在粘贴代码以供快速参考。

interface ITransport 
{ 
    void Travel(); 
} 

我的交通工厂是:

public class TransportFactory 
{ 
.... 
    internal ITransport ProvideTransport(TransportTypes transportType) 
    { 
     switch (transportType) 
     { 
      case TransportTypes.Camel: return new Camel(); 
      case TransportTypes.Horse: return new Horse(); 
      case TransportTypes.Ship: return new Ship(); 
      default: 
       return null; 
     } 
    } 
} 

我的建议后,人类已经成为为:

public class Human 
{ 
    Action<Human, string> _transportRequested; 

    public Human(Action<Human, string> transportRequested) 
    { 
     _transportRequested = transportRequested; 
    } 

    public void Travel() 
    { 
     if (_transportRequested != null) 
     { 
      var ev = _transportRequested; 
      ev.Invoke(this, GroundTypes.Plains.ToString()); 
     } 
    } 
} 

我有一个人的类厂现在的建议是因为:

public class HumanFactory 
{ 
    ITransport camel; 
    ITransport ship; 
    ITransport horse; 
    Human _human; 
    Dictionary<string, ITransport> _availableTransports; 
    event Action<Human, string> transportRequested; 

    public HumanFactory(TransportFactory tFactory) 
    { 

     horse = tFactory.ProvideTransport(TransportTypes.Horse); 
     camel = tFactory.ProvideTransport(TransportTypes.Camel); 
     ship = tFactory.ProvideTransport(TransportTypes.Ship); 
    } 

    public Human ConfigureHuman() 
    { 
     if (_availableTransports == null) 
     { 
      _availableTransports = new Dictionary<string, ITransport>(); 
      _availableTransports.Add(GroundTypes.Desert.ToString(), camel); 
      _availableTransports.Add(GroundTypes.Sea.ToString(), ship); 
      _availableTransports.Add(GroundTypes.Plains.ToString(), horse); 
     } 

     transportRequested += new Action<Human, string>(_human_transportRequested); 
     _human = new Human(transportRequested); 

     return _human; 
    } 

    void _human_transportRequested(Human human, string groundType) 
    { 
     if (_availableTransports.ContainsKey(groundType)) 
     { 
      ITransport suitableTransport = _availableTransports[groundType]; 
      suitableTransport.Travel(); 
     } 
     else 
     { 
      //code for handling below conditions goes here 
      //I don't know what to do for this type of plain? 
     } 
    } 
} 

我谈过一个映射器类映射正确运输纠正方法为(它看起来很丑,但是那是最好的,我想出了:)):

class Human_Transport_MethodMapper 
{ 
    Dictionary<GroundTypes, ITransport> _availableTransports; 
    List<EventTypes> _availableEvents; 
    event Action<Human, GroundTypes, EventTypes> transportRequested; 
    internal Action<Human, GroundTypes, EventTypes> transportRequesteddel; 
    public Human_Transport_MethodMapper(Dictionary<GroundTypes, ITransport> availableTransports, List<EventTypes> availableEvents) 
    { 
     _availableEvents = availableEvents; 
     _availableTransports = availableTransports; 
     transportRequested += human_OnAnyEventReceived; 
     transportRequesteddel = transportRequested; 
    } 
    internal void human_OnAnyEventReceived(Human human, GroundTypes groundType, EventTypes eventType) 
    { 
     if (_availableTransports.ContainsKey(groundType)) 
     { 
      ITransport suitableTransport = _availableTransports[groundType]; 
      switch (eventType) 
      { 
       case EventTypes.Travel: suitableTransport.Travel(); 
        break; 
       default: 
        break; //meaning interface's correct method has not been mapped. 
      } 

     } 
     else 
     { 
      //code for handling below conditions goes here 
      //I don't know what to do for this type of plain? 
     } 
    } 
} 

现在看到,在这种情况下,对于旅游法,如果有两个参数,那么委托签名就会改变,如果ITransport界面中有四五种方法,那么上帝可以帮助我。

我希望我在这里解释了我的问题。 感谢

编辑:我除去这个问题,一些明显的代码,以使其更具可读性,也被越来越冗长

+0

如果我简单地传递一个Itransports字典及其类型(骆驼,马,船......等),它会违反Demeter法还是依赖注入法? – shankbond

回答

0

首先,你处理非标准事件的方式是混乱并且过于复杂。您不需要将事件传递给构造函数请参阅上一个主题中关于如何简化它的最后编辑。另外,正如我在前面的主题中提到的,在大型应用程序中处理复杂事件网络的常见方法是实现EventsAggregator模式(http://codebetter.com/jeremymiller/2009/07/22/braindump-on-the-event-aggregator-pattern/)。网络上有各种各样的实现可供使用,所以我把它留给你选择一个。我将使用这个接口,例如用途:

interface IEventsAggregator 
{ 
    //sends message to network 
    void Publish(object message); 
    //adds object to the list of handlers 
    void Subscribe(object listener); 
    //removes object from the list of handlers 
    void Unsubscribe(object listener); 
} 

//listeners should implement this interface 
interface IListener<TMessage> 
{ 
    //handling logic for particular message 
    void Handle(TMessgae message); 
} 

那么你的代码进行重构:

//you do not need human factory in this example 
public class Human 
{ 
    private readonly IEventsAggregator _events; 

    //see Handle implementation for details 
    //public ITransport Transport { get; set; } 

    public Human(IEventsAggregator events) 
    { 
     _events = events; 
    } 

    public void Travel(GroundTypes type) 
    { 
     _events.Publish(new TransportRequest(this, type)); 
     //see Handle implementation for details 
     //if (Transport != null) Transport.Travel(); 
    } 
} 

public class TransportRequest 
{ 
    public Human Sender { get; set; } 
    public GroundTypes Ground { get; set; } 

    public TransportRequest(Human sensder, GroundTypes ground) 
    { 
     Sender = sender; 
     Ground = ground; 
    } 
} 

public class TravelAgency : IListener<TransportRequest>, IDisposable 
{ 
    private readonly IEventsAggregator _events; 
    private readonly TransportFactory _tFactory; 

    public TravelAgency(IEventsAggregator events, TransportFactory tFactory) 
    { 
     _events = events; 
     _events.Subscribe(this); 
     _tFactory = tFactory; 
    } 

    public void Handle(TransportRequest request) 
    { 
     var transort = _tFactory.ProvideTransport(...); 
     //insert the handling logic here 
     //there are two ways to handle this message: 
     //1) you give human no control over (and no knowledge of) Transport 
     //and simply call transport.Travel(request.Sender); here 
     //2) or you add ITransport property to Human class 
     //and do only the assignation here 
     //request.Sender.Transport = transport; 
     //and then let the human manage Transport object 
    } 

    public void Dispose() 
    { 
     _events.Unsubscribe(this); 
    } 
} 

这大概是我会做,如果我需要stricktly独立的逻辑出于某种原因。对于这样简单的任务来说可能有点复杂,但我认为它对于大型应用来说是一个很好的基础。 :)可能还有其他方法。

+0

“看到我上次在上一个主题中的编辑”,我无法导航到您上一个主题? – shankbond

+0

如果我简单地传递一个Itransports字典及其类型(骆驼,马,船......等),它会违反得墨忒耳定律还是依赖注入法? (也请修正上面提到的链接) – shankbond

+0

http://codereview.stackexchange.com/a/28405/24349 –

相关问题