如何在实现共享通用方法的接口时删除代码重复
How to remove code duplication when implementing interfaces that share common methods
编辑
我改写了这个问题,以便更好地反映我正在尝试做的事情
我正在尝试创建一套 class 都继承自 1 "superclass" 或 "baseclass".
但是我正在寻找一种方法来解决必须在每个 class 中为每个方法实现代码,因为它似乎有很多重复。
这里是超级 class:
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);
}
这里是派生的例子class:
public class TextBox: WebObject, IWriteable, IReadable
{
}
当然上面class有错误。它不实现 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 中进行多重继承。所以我最初的想法是简单地创建一套静态 classes 以及此处显示的 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 "";
}
}
然后将我的文本框 class 更改为以下内容:
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.
完成您所要求的最简洁的方法是在您的基础 class 中实施 protected
辅助方法,将 "a lot of duplication" 的问题分解成更小的部分,这些部分可以组合成你的具体方法实现,像这样:
public abstract class WebObject {
protected void SetTextImpl() { /* Implementation */ }
protected void GetTextImpl() { /* Implementation */ }
}
然后在派生的 classes 中,仅实现适用的接口和适当的方法:
public class TextBox: WebObject, IWriteable, IReadable {
public void SetText() { SetTextImpl(); }
public void GetText() { GetTextImpl(); }
}
public class Span: WebObject, IReadable {
public void GetText() { GetTextImpl(); }
}
如果您知道所有子classes 都将是 IReadable,您可以进一步简化:
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 {
}
如果这两个方法的代码总是相同或大部分相同,您可以创建另一个抽象 class(例如:WebObjectReadWrite),它继承自 WebObject 并实现接口。
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
{
}
但是,这可能会导致多重继承问题或没有意义的继承关系。另一种选择是使用 strategy pattern(以某种方式)将读/写操作委托给其他可以重用的 classes。
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 和 IWriteable 的实现。但是,它确实允许您重用 IReadable 和 IWriteable classes.
编辑 我改写了这个问题,以便更好地反映我正在尝试做的事情
我正在尝试创建一套 class 都继承自 1 "superclass" 或 "baseclass".
但是我正在寻找一种方法来解决必须在每个 class 中为每个方法实现代码,因为它似乎有很多重复。
这里是超级 class:
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);
}
这里是派生的例子class:
public class TextBox: WebObject, IWriteable, IReadable
{
}
当然上面class有错误。它不实现 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 中进行多重继承。所以我最初的想法是简单地创建一套静态 classes 以及此处显示的 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 "";
}
}
然后将我的文本框 class 更改为以下内容:
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.
完成您所要求的最简洁的方法是在您的基础 class 中实施 protected
辅助方法,将 "a lot of duplication" 的问题分解成更小的部分,这些部分可以组合成你的具体方法实现,像这样:
public abstract class WebObject {
protected void SetTextImpl() { /* Implementation */ }
protected void GetTextImpl() { /* Implementation */ }
}
然后在派生的 classes 中,仅实现适用的接口和适当的方法:
public class TextBox: WebObject, IWriteable, IReadable {
public void SetText() { SetTextImpl(); }
public void GetText() { GetTextImpl(); }
}
public class Span: WebObject, IReadable {
public void GetText() { GetTextImpl(); }
}
如果您知道所有子classes 都将是 IReadable,您可以进一步简化:
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 {
}
如果这两个方法的代码总是相同或大部分相同,您可以创建另一个抽象 class(例如:WebObjectReadWrite),它继承自 WebObject 并实现接口。
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
{
}
但是,这可能会导致多重继承问题或没有意义的继承关系。另一种选择是使用 strategy pattern(以某种方式)将读/写操作委托给其他可以重用的 classes。
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 和 IWriteable 的实现。但是,它确实允许您重用 IReadable 和 IWriteable classes.