我有一个“武器”类,根据其分类,它具有不同的行为。可以在运行时更改行为,并且可以用其他行为替换行为。 (对于那些知道的人,我正在描述一种蠕虫武器:世界末日)。
通常我会创建不同的“Weapon”子类来实现特定的行为,但由于它可以在运行时更改,我不能使用这样的“静态典型化”。
我想到了类似下面的类武器(C#)。
public class Weapon
{
public AirstrikeSettings _airstrikeSettings;
public MineSettings _mineSettings;
public LauncherSettings _launcherSettings,
}
* Settings类包含定义确切行为的参数。
在运行时,必须检查3个设置实例中的哪一个不为空,以找出这是什么武器分类。如果分类发生变化,例如从Mine到Airstrike,则MineSettings设置为null并初始化AirstrikeSettings。
这是设计此案例的正确方法还是我有极端的设计问题?
PS:如果您有兴趣,这是我想在课堂上反映的结构:http://worms2d.info/Project_X/Weapon_file_block
答案 0 :(得分:1)
正如您已经说过的,Weapon
级别的基于继承的方法将不允许您在运行时更改行为。
我建议您查看 Strategy design pattern 。它允许您在运行时更改类的行为,并且可以避免在类本身中包含大量if语句。
因此,在您的示例中,Weapon
类将成为策略的上下文和设置。对于每种类型的设置,您没有三个单独的成员,而是只有一个成员用于当前设置。如果确保始终设置此项,则不必检查null,如果要执行特定于设置的行为,则始终调用当前设置。为了使其工作,设置需要基于共同的结构。
为了能够从外部设置行为,您可以为可从类外部访问的当前设置创建属性,从而允许调用者在运行时更改设置。
所以你的样本看起来与此类似:
// base strategy, can also be an abstract class if you want to share
logic between the settings
public interface IWeaponSettings
{
// Definition of common structure for the behaviors
void BehaveInSpecialWay();
// ...
}
public class AirstrikeSettings: IWeaponSettings
{
// Implementation for Airstrike
public void BehaveInSpecialWay()
{
// Airstrike
}
}
public class MineSettings : IWeaponSettings
{
// Implementation for Mining
public void BehaveInSpecialWay()
{
// Mining
}
}
// ...
public class Weapon
{
// Constructor that takes the initial settings as an input
public Weapon(IWeaponSettings settings)
{
Settings = settings
}
// Public property that can be used to change behavior.
// You might want to check against null in the setter
public IWeaponSettings Settings { get; set; }
public void DoSomething()
{
Settings.BehaveInSpecialWay();
}
}
请注意,如果某些设置不支持某些行为,他们仍然需要实现它们,但只是不执行任何操作或返回默认值。
答案 1 :(得分:0)
我建议你创建一个抽象的Weapon
类,以及三个派生类:AirstrikeWeapon
,MineWeapon
和LauncherWeapon
。这些子类中的每一个都可以有自己的设置。然后,将Attack
方法添加到基类,并使用每个派生类中所需的任何逻辑来实现它。然后,在运行时,每个蠕虫都有一个Weapon
成员,可以将其设置为当前使用的武器实例。
顺便说一下,这叫做多态。
答案 2 :(得分:0)
简单地说,如果我必须检查null
在运行时知道类的类型,那么Inheritance
正在做什么。
在您的情况下,您可以定义一个抽象类Settings
,它将是这三个类的父类。然后,课程Weapon
将仅包含课程Settings
的引用。请参阅以下代码:
public abstract class Settings
{
}
public class AirstrikeSettings : Settings
{
}
public class MineSettings : Settings
{
}
public class LauncherSettings : Settings
{
}
public class Weapon
{
public Settings Settings { get; set; } // as this member is public, it can be declared as property
}