如何设计具有不同子结构的类

时间:2014-03-09 12:56:11

标签: c# design-patterns inheritance

我有一个“武器”类,根据其分类,它具有不同的行为。可以在运行时更改行为,并且可以用其他行为替换行为。 (对于那些知道的人,我正在描述一种蠕虫武器:世界末日)。

通常我会创建不同的“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

3 个答案:

答案 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类,以及三个派生类:AirstrikeWeaponMineWeaponLauncherWeapon。这些子类中的每一个都可以有自己的设置。然后,将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
}