如何在实现共享常用方法的接口时删除代码重复

本文关键字:接口 删除 代码 方法 实现 共享 常用 | 更新日期: 2023-09-27 18:10:32

>编辑我改写了这个问题,以便更好地反映我试图做什么

我正在尝试创建一套都继承自 1 个"超类"或"基类"的类。

但是,我正在寻找一种解决必须在每个类中实现每个方法的代码的方法,因为它似乎有很多重复

这是超级类:

public abstract class WebObject
{
    string Id { get; set; }
    string Name { get; set; }
    public void Click() { Console.WriteLine("Clicking object"); }
    public string GetAttribute() { return "An attribute"; }
    public void SetAttribute(string attribute, string value)
    {
        //code to set attribute
    }
}

我还创建了几个接口:

interface IReadable
{
    string GetText();
}
interface IWriteable
{
    void SetText(string value);
}

下面是一个派生类示例:

public class TextBox: WebObject, IWriteable, IReadable
{

}

当然,上面的类包含一个错误。它不实现 IWriteable 或 IReadable。

所以我可以做这样的事情:

public class TextBox: WebObject, IWriteable, IReadable
{
    public void SetText(string value)
    {
        //Implemented code
    }
    public string GetText()
    {
        //Implemented code
        return "some value";
    }
}

这将编译得很好...然而,这里的问题是SetText和GetText包含大量代码。我不想每次想要实现该方法时都必须复制它。我宁愿只编写一次代码,并在我需要使用该方法时调用它。

我知道我们不能在C#和Java中进行多重继承。所以我最初的想法只是使用如下所示的 SetText 和 GetText 的代码创建一套静态类:

public static class Setter
{
    public static void SetText(string value)
    {
        //Code to set text
    }
}
public static class Getter
{
    public static string GetText()
    {
        //Code to get text
        return "";
    }
}

然后将我的 TextBox 类更改为以下内容:

public class TextBox: WebObject, IWriteable, IReadable
{
    public void SetText(string value)
    {
        Setter.SetText(value);
    }
    public string GetText()
    {
        return Getter.GetText();
    }
}

我不禁觉得这是一个相当冗长的解决方案。它实现了我想要的,即 TextBox 具有原版方法加上它自己实现的 2

但我的问题是,我可以使用更简洁的设计来实现相同的目标吗?

脚注

每个对象实际上都实现了几种常用方法。以TextBox,ComboBox和SelectBox为例,它们都应该能够设置文本,但是只有CombBox和SelectBox应该能够使用Select。

如何在实现共享常用方法的接口时删除代码重复

执行您所要求的操作的最干净方法是在基类中实现protected帮助程序方法,这些方法将"大量重复"的问题分解为可以在具体方法实现中组合的较小部分,如下所示:

public abstract class WebObject {
  protected void SetTextImpl() { /* Implementation */ } 
  protected void GetTextImpl() { /* Implementation */ } 
}

然后在派生类中,仅实现适用的接口和适当的方法:

public class TextBox: WebObject, IWriteable, IReadable {
  public void SetText() { SetTextImpl(); }
  public void GetText() { GetTextImpl(); }
}
public class Span: WebObject, IReadable {
  public void GetText() { GetTextImpl(); }
}

如果您知道所有子类都是不可分割的,则可以进一步简化:

public abstract class WebObject : IReadable {
  protected void SetTextImpl() { /* Implementation */ } 
  protected void GetTextImpl() { /* Implementation */ } 
  // Implement IReadable -- this could be combined with GetTextImpl() but
  // is implemented separately for consistency.
  public void GetText() { GetTextImpl(); }
}
public class TextBox: WebObject, IWriteable {
  public void SetText() { SetTextImpl(); }
}
public class Span: WebObject, IReadable {
}

如果这两个方法的代码始终相同或基本相同,则可以创建另一个从 WebObject 继承并实现接口的抽象类(例如:WebObjectReadWrite(。

public abstract class WebObjectReadWrite : WebObject, IReadable, IWritable
{
    // Could be made virtual if some subclasses need to overwrite default implementation.
    public void Read() 
    {
        // Implementation
    }
    // Could be made virtual if some subclasses need to overwrite default implementation.
    public void Write() 
    {
        // Implementation
    }
}
public class TextBox : WebObjectReadWrite
{
}

但是,这可能会导致多个继承问题或没有意义的继承关系。另一种选择是使用策略模式(以方式(将读/写操作委托给可以重用的其他类。

public class TextBox : WebObject, IReadable, IWriteable
{
    private IReadable _readable = new TextReader();
    private IWriteable _writeable = new TextWriter();
    public void Read() 
    {
        _readable.Read();
    }
    public void Write() 
    {
        _writable.Write();
    }
}
public class Span : WebObject, IReadable
{
    // Reused class.
    private IReadable _readable = new TextReader();        
    public void Read() 
    {
        _readable.Read();
    }
}
public class TextReader : IReadable
{
    public void Read()
    {
        // Reusable implementation
    } 
}

这不完全是策略模式,因为您不允许调用方选择"IReadable"和"I"riteable的实现。但是,它确实允许您重用 IReadable 和 IWriteable 类。