私は@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;
}
}
}
(この例は、すべてのプログラミングのベスト プラクティスに従っているわけではないことに注意してください。このコードをそのまま実装することはお勧めしません。たとえば、アクション パラメーターは文字列よりも列挙型の方が適切であり、ブール値ではなくある種の CommandResult を返します。 . インスピレーションのみに使用してください。)