假设我有许多具有不同签名的方法。基于一些外部代码,可以调用所有这些方法 。您可能会将它们视为一些事件处理程序。
现在我应该有两个实现:
我当然可以为所有可能的处理程序声明一个接口,但是我必须在每个实现中创建空方法(处理程序)。即使是那些我不想/不能处理的事件。
我正在考虑做以下事情:
abstract class Base
{
public virtual void First(int i, double d) { /* no implementation */ }
public virtual void Second(double d) { /* no implementation */ }
public virtual void Third(string s, int i) { /* no implementation */ }
}
class Child : Base
{
public override void First(int i, double d) { /* implementation */ }
public override void Second(double d) { /* implementation */ }
}
class AnotherChild : Base
{
public override void Second(double d) { /* implementation */ }
public override void Third(string s, int i) { /* implementation */ }
}
这种方法迫使我为基本抽象类中的所有可能的处理程序创建空实现。
你能推荐更好的东西吗?一种不需要生成大量空方法的方法吗?
我使用的是C#2.0,无法使用该语言的较新版本来完成此任务。
答案 0 :(得分:4)
我同意@usr - 我没有看到空函数的问题。如果要调用函数,则必须存在。如果在某些情况下它什么也不做,那么该函数应该是空的。具有空函数的基类与需要反复执行相同空函数的接口相比,似乎是一个非常好的主意。
如果您正在寻找替代方案,可以考虑Chain of Responsibility设计模式。您可以调用常规函数,然后参数化所需的行为,而不是调用特定的函数。然后,您可以将对象链接在一起(不同情况下的不同链),并让它们有机会处理行为。如果他们都没有处理它,那么没有任何事情发生。
这在某些情况下可以很好地工作,但是实现非常简单和优雅的基类方法会更复杂。小心不要过度工程。
示例强>
以下是基于您在问题中提供的示例实现命令链的示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2 {
interface ICommand {
bool Execute( string action, params object[] parameters );
}
class Program {
static void Main( string[] args ) {
CommandChain l_chain1 = new CommandChain( new FirstCommand(), new SecondCommand() );
CommandChain l_chain2 = new CommandChain( new SecondCommand(), new ThirdCommand() );
// Chain 1
if ( l_chain1.Execute( "first", (int) 1, (double) 1.1 ) )
Console.WriteLine( "Chain 1 executed First" );
else
Console.WriteLine( "Chain 1 did not execute First" );
if ( l_chain1.Execute( "second", (double) 1.2 ) )
Console.WriteLine( "Chain 1 executed Second" );
else
Console.WriteLine( "Chain 1 did not execute Second" );
if ( l_chain1.Execute( "third", "4", (int) 3 ) )
Console.WriteLine( "Chain 1 executed Third" );
else
Console.WriteLine( "Chain 1 did not execute Third" );
// Chain 2
if ( l_chain2.Execute( "first", (int) 1, (double) 1.1 ) )
Console.WriteLine( "Chain 2 executed First" );
else
Console.WriteLine( "Chain 2 did not execute First" );
if ( l_chain2.Execute( "second", (double) 1.2 ) )
Console.WriteLine( "Chain 2 executed Second" );
else
Console.WriteLine( "Chain 2 did not execute Second" );
if ( l_chain2.Execute( "third", "4", (int) 3 ) )
Console.WriteLine( "Chain 2 executed Third" );
else
Console.WriteLine( "Chain 2 did not execute Third" );
Console.ReadKey( true );
}
}
class CommandChain {
private ICommand[] _commands;
public CommandChain( params ICommand[] commands ) {
_commands = commands;
}
public bool Execute( string action, params object[] parameters ) {
foreach ( ICommand l_command in _commands ) {
if ( l_command.Execute( action, parameters ) )
return true;
}
return false;
}
}
class FirstCommand : ICommand {
public bool Execute( string action, params object[] parameters ) {
if ( action == "first" &&
parameters.Length == 2 &&
parameters[0].GetType() == typeof( int ) &&
parameters[1].GetType() == typeof( double ) ) {
int i = (int) parameters[0];
double d = (double) parameters[1];
// do something
return true;
} else
return false;
}
}
class SecondCommand : ICommand {
public bool Execute( string action, params object[] parameters ) {
if ( action == "second" &&
parameters.Length == 1 &&
parameters[0].GetType() == typeof( double ) ) {
double d = (double) parameters[0];
// do something
return true;
} else
return false;
}
}
class ThirdCommand : ICommand {
public bool Execute( string action, params object[] parameters ) {
if ( action == "third" &&
parameters.Length == 2 &&
parameters[0].GetType() == typeof( string ) &&
parameters[1].GetType() == typeof( int ) ) {
string s = (string) parameters[0];
int i = (int) parameters[1];
// do something
return true;
} else
return false;
}
}
}
(请注意,此示例并未遵循每个编程最佳实践 - 我不建议完全实现此代码。例如,action参数可能更好作为枚举而非字符串,并返回某种CommandResult而不是而不是布尔值。仅用于灵感。)
答案 1 :(得分:1)
只是旁注:如果这是出于测试目的,您可以模拟界面并立即执行几乎没有代码的无操作实现。您也可以类似地实现仅部分实现接口的类中所有缺少的方法。不是为了测试 - 你也可以在生产中使用它,但是......在产品中使用模拟有点气味,并且对于“handler-ish”合同有一个样板基础空实现实际上并不邪恶,实际上它是一件好事作为进一步代码的基础 - 就像Cyborgx37已经注意到的那样。