我有一个我想解决的设计问题。
我有一个接口,我们称之为IProtocol
,它由两个独立的类实现。我们在这里查看600多行代码。他们所做的绝大多数事情是相同的,除以外的某些特定领域,例如DiffStuff();
目前的结构是这样的:
public class Protocol1 : IProtocol
{
MyInterfaceMethod1()
{
Same1();
DiffStuff();
Same2();
}
}
和
public class Protocol2 : IProtocol { MyInterfaceMethod1() { Same1(); Same2(); } }
如果我将两个协议分开,我担心会出现复制粘贴错误和代码重复的典型问题。我们讨论的是每行600行代码,而不是一些简单的方法。
我正在考虑将Protocol1的实现更改为从protocol2继承,就像这样(Protocol2基本上保持不变,除了我必须将Same1()
和Same2()
包装到私有方法中。)
public class Protocol1 : Protocol2
{
void Same1()
{
base.Same1();
}
void Same2()
{
base.Same2();
}
MyInterfaceMethod1()
{
Same1();
DiffStuff();
Same2();
}
}
这是处理这个问题的正确方法吗?
修改 很多人帮助我解决了这个问题,感谢他们的明确理解。在我的例子中,两个对象的类型不同,即使它们的大部分实现都是共享的,所以我使用Bobby's suggestion来使用抽象基类,创建小方法来封装类之间的更改。另外感谢:
答案 0 :(得分:7)
/// <summary>
/// IProtocol interface
/// </summary>
public interface IProtocol
{
void MyInterfaceMethod1();
void Same1();
void Same2();
}
...然后
public abstract class ProtocolBase : IProtocol
{
#region IProtocol Members
public void MyInterfaceMethod1()
{
// Implementation elided...
}
public void Same1()
{
// Implementation elided...
}
public void Same2()
{
// Implementation elided...
}
public abstract void DiffStuff();
#endregion
}
最后...
public sealed class Protocol1 : ProtocolBase
{
public override void DiffStuff()
{
// Implementation elided...
}
}
public sealed class Protocol2 : ProtocolBase
{
public override void DiffStuff()
{
// Implementation elided...
}
}
答案 1 :(得分:5)
不完全。添加Same1和Same2方法没有意义,您可以从ProtocolBase继承它们。并且DiffStuff()应该是一个虚方法,以便您可以覆盖它并赋予它不同的行为。
答案 2 :(得分:4)
你非常接近于描述template method pattern,它有很长的血统作为解决像你这样的问题的有效解决方案。
但是,您应该考虑使用合成而不是继承。 The two approaches offer different advantages and disadvantages,但组成通常(通常是?)更好 * :
public class Protocol {
private ISpecialHandler specialHandler;
public Protocol() {}
public Protocol(ISpecialHandler specialHandler) {
this.specialHandler = specialHandler;
}
void Same1() {}
void Same2() {}
public void DoStuff() {
this.Same1();
if (this.specialHandler != null) {
this.specialHandler.DoStuff();
}
this.Same2();
}
}
然后,调用者可以传入提供专门算法的对象实例(strategies)来处理手头的任何情况:
Protocol protocol1 = new Protocol(new DiffStuffHandler());
protocol1.DoStuff();
* 请参阅Patterns I Hate #2: Template Method,详细解释为什么在您的情况下,合成通常优于继承。
答案 3 :(得分:0)
我更好的设计(在我看来)
public abstract class Protocol_common : IProtocol
{
MyInterfaceMethod1()
{
Same1();
DiffStuff();
Same2();
}
abstract void DiffStuff();
}
public class Protocol1 : Protocol_common
{
DiffStuff()
{
/// stuff here.
}
}
public class Protocol2 : Protocol_common
{
DiffStuff()
{
/// nothing here.
}
}
(这实际上比正确的C#更多的伪代码,但我达到了高点)
答案 4 :(得分:0)
您可能想要考虑这种类型的模式是否有效:
public class ProtocolHelper
{
public void Same1() {}
public void Same2() {}
}
public class Protocol1 : IProtocol
{
private readonly ProtocolHelper _helper = new ProtocolHelper();
void MyInterfaceMethod1()
{
_helper.Same1();
DiffStuff();
_helper.Same2();
}
}
您可以通过查看是否可以为“ProtocolHelper”类找到一个好名字来判断这是否有意义。如果一个名字自然来自你的逻辑,那么这是打破课程的好方法。您可能需要将一些依赖项(例如私有字段)作为参数传递给方法,以使其工作。
答案 5 :(得分:-1)
我同意MathEpic。我会使用Template method模式。