条件関数の詳細を知らなくても、2 つの選択肢があります。
1つは、次のようなことができます
if (f.GetType() == typeof(FireBall))
{
fireBall = (FireBall)f;
fireBall.FireTheFireBall();
}
else if (f.GetType() == typeof(Heal))
...
または、アビリティに抽象の Activate メソッドを含めることができます。このメソッドは、すべての派生クラスでオーバーロードする必要があります。
class Fireball
{
public override void Activate()
{
//do fireball specific things
this.FireTheFireBall();
}
public void FireTheFireBall() {...}
}
class Heal
{
public override void Activate()
{
//do healing specific things
this.ApplyTheBandage();
}
...
}
abstract class Ability
{
public abstract void Activate();
}
void condition(Ability f){
f.Activate(); //runs the version of Activate of the derived class
}
その後、Ability で動作するものは someAbility.Activate() を呼び出すことができ、派生クラスによって提供される実装が実行されます。
また、抽象クラスのようなインターフェースについても勉強する必要があります。インターフェイスの利点は、複数のインターフェイスを実装できることですが、継承できるのは 1 つの基本抽象クラスのみに限定されます。Turn と Pull 機能を持つ IKnob インターフェイスについて考えてみましょう。IKnob を実装する Drawer クラス、Door クラス、Turn を実装してトラップをアクティブにする TrappedDoor クラスがあるとします。プレイヤーがドアに近づき、そのドアの [使用] ボタンを押して、open 関数にオブジェクト Open(IKnob ノブ) を渡します。
void Open(IKnob knob)
{
knob.Turn();
knob.Pull();
}
class TrappedDoor:IKnob,IMaterial,ISomethingElse,IHaveTheseOtherCapabilitiesAsWell
{
private bool TrapAlreadySprung{get;set;}
//more complex properties would allow traps to be attached either to the knob, or the door, such that in one case turning the knob activates the trap, and in the other, Pull activates the trap
public Turn() {
if(! TrapAlreadySprung)
{
MessageBox("You hit your head, now you're dead");
}
}
}
何かにインターフェイスがあるかどうかを確認する方法があるため、プレーヤーがアイテムに近づいて話しかけようとした場合、オブジェクトに ICanTalk インターフェイスがあるかどうかを確認できます。ある場合は object.GetReply("Hello") を呼び出します。オブジェクトは応答できます。そのため、必要に応じて話すドアや岩を設置できます。ICanTalk インターフェイス メソッドを使用して、物事との対話/応答の表示などを処理するすべてのコードを取得すると、他のクラスが ICanTalk を実装し、それぞれがどのように応答して対話するかを決定します。この概念は「関心の分離」として知られており、より再利用可能なコードを作成するのに役立ちます。
重要なことは、そのインターフェイスでのみ動作するコード、アルゴリズム、関数などを作成できることです。そうすれば、そのコードがインターフェイスで動作するようになると、そのインターフェイスを任意のクラスで使用できるようになります。そのクラスは既存のコードを活用できます。
つまり、condition
関数が IAbility インターフェイスを取り込んだ場合、そのコードが機能するようになると、作成した IAbility を実装するクラスを条件関数に渡すことができます。条件関数は、想定されているすべての処理を担当し、IAability を実装するクラスは、実装されたメソッド内で固有のものをすべて処理します。
もちろん、抽象クラスまたはインターフェースを実装するクラスは、必要なメソッドを実装する必要があるため、コードを複製しているように感じることがあります。たとえば、TrappedDoor や Door などの類似のクラスがある場合、トラップが設定されていないか、すでに発生している場合、TrappedDoor は通常の Door と同じように動作する可能性があります。したがって、この場合は Door から継承するか、非公開の Door プロパティ (「コンポジション」と呼ばれます) を持つことができます。トラップがすでに発生している場合は、ベース Door クラスまたはプライベート Door プロパティを呼び出して .Turn を呼び出し、トラップがアクティブでない場合に通常のドアのデフォルトの動作を再利用することができます。
オブジェクトがインターフェイスを実装しているかどうかをテストする
個人的には、継承ではなく、主にインターフェイスと構成を使用します。継承がひどいというわけではありませんが、継承階層はすぐに非常に複雑になる可能性があります。