当“更喜欢组合而不是继承”时生成传递代码

时间:2010-01-27 21:33:54

标签: c# visual-studio design-patterns code-generation

问题

假设我试图将手机模型化为普通手机和PDA的组合。这是一种多重继承方案(手机手机,而 PDA)。由于C#不支持多重继承,因此这几乎需要某种组合。另外,让我们说我还有其他理由支持作曲。

我一直想知道:是否有任何工具可以自动生成所有不可避免的传递代码?

让我用一些实际的代码充实我的例子:

接口

public interface IPhone
{
    public void MakeCall(int phoneNumber);
    public void AnswerCall();
    public void HangUp();
}

public interface IPda
{
    public void SendEmail(string[] recipientList, string subject, string message);
    public int LookUpContactPhoneNumber(string contactName);
    public void SyncWithComputer();
}

实现:

public class Phone : IPhone
{
    public void MakeCall(int phoneNumber) { // implementation }
    public void AnswerCall() { // implementation }
    public void HangUp() { // implementation }
}

public class Pda : IPda
{
    public void SendEmail(string[] recipientList, string subject, string message) { // implementation }
    public int LookUpContactPhoneNumber(string contactName) { // implementation }
    public void SyncWithComputer() { // implementation }
}

CellPhone类

public class CellPhone : IPhone, IPda
{
    private IPhone _phone;
    private IPda _pda;

    public CellPhone(IPhone phone, IPda pda)
    {
        _phone = phone;
        _pda = pda;
    }

    public void MakeCall(int phoneNumber)
    {
        _phone.MakeCall(phoneNumber);
    }

    public void AnswerCall()
    {
        _phone.AnswerCall();
    }

    public void HangUp()
    {
        _phone.HangUp();
    }

    public void SendEmail(string[] recipientList, string subject, string message)
    {
        _pda.SendEmail(recipientList, subject, message);
    }

    public int LookUpContactPhoneNumber(string contactName)
    {
        return _pda.LookUpContactPhoneNumber(contactName);
    }

    public void SyncWithComputer()
    {
        _pda.SyncWithComputer();
    }
}

编写CellPhone类既繁琐又容易出错:

所有这一课确实充当了PhonePda类的管道。实际上没有理由要求人工努力输入所有这些传递语句(如_phone.MakeCall(phoneNumber);)。它只暴露了几个成员字段的公共接口。

问题

  1. 是否有一个工具(最好是免费的:))可以让我免于容易出错的编写传递方法的麻烦?我知道我可以使用VS自动生成存根,但这只能让我获得一半。

  2. 您能评价此功能的可行性和可取性吗?是否值得向微软提出添加此类代码生成的建议?如果我这样做,你会投票吗?如果没有,你有什么反对意见?

  3. 修改

    每个人似乎都在说同样的话:为什么我不把_phone_pda变成公共财产?我对此的反对意见是它违反了“最少知识原则”。我的CellPhone课程的客户应该只做手机所做的事情,不应该处理哪些功能是Phone功能以及哪些是Pda功能。这会产生额外的依赖关系,并使CellPhone界面的功能不那么明显。

    另外,不要只关注这个例子。如果我正在编写适配器怎么办?它可能包含几个只是传递的接口成员,但它也可能包含一些具有唯一实现的唯一成员。我相信在很多情况下,传递代码是好东西,我只是不喜欢写它。

5 个答案:

答案 0 :(得分:17)

是的,您可以使用精彩的VS加载项ReSharper

生成方法

从代码生成菜单中选择“generate delegating methods”选项(使用默认快捷方式的Alt-Insert)。

如果你有一个实现接口的类,包含一个实现相同接口的字段,R#将为你提供一个生成传递代码的选项。它也可以与任意数量的接口一起使用。

答案 1 :(得分:2)

之前我已经看过这个建议(不一定是Stack Overflow)。不久前。我相信作者创建了一个Connect问题,虽然我不知道它的状态。

建议的语法是以下之一:

public class CellPhone : IPhone, IPda
{
    private readonly IPhone _phone implements IPhone;
    private readonly IPda _pda : IPda;

    // ...
}

答案 2 :(得分:1)

为之前提供的答案添加一些视觉效果和细节。

  1. 将接口添加到您希望成为包装类的类

    class MyWebElement : IWebElement { }
    
    1. 查找/点击"委托实施" YourInterfaceHere"到一个新的领域 Delegate Implementation
      1. 选择您的选项 Delegate options
        1. 点击完成并享受您的新课程

          class MyWebElement : IWebElement
          {
              private IWebElement _webElementImplementation;
              public IWebElement FindElement(By @by)
              {
                  return _webElementImplementation.FindElement(@by);
              }
          
              public ReadOnlyCollection<IWebElement> FindElements(By @by)
              {
                  return _webElementImplementation.FindElements(@by);
              }
          
              public void Clear()
              {
                  _webElementImplementation.Clear();
              }
          
              public void SendKeys(string text)
              {
                  _webElementImplementation.SendKeys(text);
              }
          
              public void Submit()
              {
                  _webElementImplementation.Submit();
              }
          
              public void Click()
              {
                  _webElementImplementation.Click();
              }
          
              public string GetAttribute(string attributeName)
              {
                  return _webElementImplementation.GetAttribute(attributeName);
              }
          
              public string GetCssValue(string propertyName)
              {
                  return _webElementImplementation.GetCssValue(propertyName);
              }
          
              public string TagName
              {
                  get { return _webElementImplementation.TagName; }
              }
          
              public string Text
              {
                  get { return _webElementImplementation.Text; }
              }
          
              public bool Enabled
              {
                  get { return _webElementImplementation.Enabled; }
              }
          
              public bool Selected
              {
                  get { return _webElementImplementation.Selected; }
              }
          
              public Point Location
              {
                  get { return _webElementImplementation.Location; }
              }
          
              public Size Size
              {
                  get { return _webElementImplementation.Size; }
              }
          
              public bool Displayed
              {
                  get { return _webElementImplementation.Displayed; }
              }
          }
          

答案 3 :(得分:0)

您可能需要检查this article,它将进入C#中的伪多重继承版本。

答案 4 :(得分:-1)

有趣的问题。 CellPhone类是否真的可以依赖现有的具体IPhone类提供的IPhone方法的实现?或者,CellPhone更有可能需要一些支持这些方法的自定义代码吗?

查看你的代码(虽然我对你的要求不太了解)让我想写下这样的东西:

public class CellPhone 
{
    private Phone _phone;
    private Pda _pda;

    public CellPhone(Phone phone, Pda pda)
    {
        _phone = phone;
        _pda = pda;
    }

    public IPhone getPhone()
    {
        return _phone;
    }

    public IPda getPda()
    {
        return _pda;
    }

    public void MakeCall(string contactName) {
        int phoneNumber = _pda.LookUpContactPhoneNumber(contactName);
        _phone.MakeCall(phoneNumber);
    }

}

问题2:

我真的不喜欢自动生成的代码。即使机器生成它 - 并且没有错误 - 您仍将负责维护它。那些方法看起来很像噪音。