对象A有一个对象B列表,对象B改变A类的正确方法?

时间:2014-08-05 21:26:03

标签: c# oop game-engine

我已经尽力自己研究这个问题,但我一直找不到好的答案。很可能是因为我不知道提出问题的正确方法。所以我只是把所有东西扔到那里。

这是我所拥有的两个班级的基本结构。 (显然不是实际的代码。)

class ship
{
    public int baseStat = 0;    //I want this to be protected
    public int derivedStat = 0; //This should also be protected
    public int DerivedStat{ get { return derivedStat ; } }

    private List<Component> components;

    public void DeriveStats()
    {
        foreach(Component component in components)
        {
            component.DeriveStats(this);
        }
    }
}

class Component
{
    public void DeriveStats(Ship ship)
    {
        ship.derivedStat = ship.baseStat + 5;
    }
}

这一切都运行得很好,我有许多不同类型的Component子类,它们对船舶和它的统计数据做了不同的事情,但是通过这种设置,所有统计数据都可以在船舶类之外查看和修改。设计明智,这看起来并不正确,坦率地说,它让我疯狂。

我可以采用更清洁/更正确的方法吗?

编辑 -

非常感谢所有评论并给出答案的人,这是一个巨大的帮助。如果其他人偶然发现了这个问题,那么我就是如何解决这个问题的。

abstract class Ship
{
    //Locking variable that only allows the ship's stats to be updated when true
    private bool _isModifying = false;

    //General Stats that define a ship******************************

    //Layers of shields
    protected int baseShields;
    public int DerivedShields
    {
        get{ return DerivedShields; }
        set
        {
            if (_isModifying)
                DerivedShields = value;
            else
                throw (new Exception("Ship stats cannot be modified outside the ship class."));
        }
    }

    //**************************************************************

    protected List<Component> installedComponents;

    public void DeriveStats()
    {
        _isModifying = true;

        foreach (Component component in installedComponents)
        {
            component.DeriveStats(this);
        }

        _isModifying = false;
    }
}

class BasicShield : Component
{
    public override void DeriveStats(Ship ship)
    {
        ship.DerivedShields = ship.DerivedShields + 1;
    }
}

6 个答案:

答案 0 :(得分:1)

Ship添加允许其他人更改Ship的方法,但赋予Ship责任并确保其自身一致性的能力。这意味着

  1. 外部各方可以请求更新Ship,但Ship可以拒绝此类请求,如果他们违反了某些约束(或Ship只是感觉不喜欢更新原因)。
  2. 您可以为这些方法提供传达操作语义的名称,同时将Ship的实现细节与程序的其余部分分离。您可以自由地改变表示Ship内部状态的方式。
  3. 修改

    如果您希望每个Component实现确定新统计数据的算法,您可以

    1. 使船舶的属性为只读(必须为组件显示它们才能进行计算)
    2. 使组件的DeriveStats(...)方法返回计算值
    3. 让船舶本身调用DeriveStats(...)并相应地更新其值。
    4. 这具有额外的好处,即船舶负责汇总来自不同组件的结果。由于组件彼此不了解,他们如何协调谁决定船舶的统计数据?

答案 1 :(得分:0)

我可以想到两种方式

组件应该计算东西(yr情况下的统计数据)并返回它。 ship类使用返回值

更新自身
    ...
    public void DeriveStats()
    {
        foreach(Component component in components)
        {
            derivedStat = component.DeriveStats(this);

        }
    }


class Component
{
    public int DeriveStats(Ship ship)
    {
        return ship.baseStat + 5;
    }
}

该船具有组件调用的UpdateStats方法。

    ...
    public void DeriveStats()
    {
        foreach(Component component in components)
        {
            component.DeriveStats(this);
        }
    }
}

class Component
{
    public void DeriveStats(Ship ship)
    {
        ship.UpdateStats(ship.baseStat + 5);
    }
}

答案 2 :(得分:0)

您可以使用属性来保持相同的基本属性,并根据其组件计算船舶的有效统计数据。

class Ship
{
    private int _baseStat = 0;    //I want this to be protected
    public int CalculatedStat
    {   
        get
        {
            int result = _baseStat;        
            foreach(Component component in components)
            {
                result += component.Modifier 
                // you'll have to add modifier to Component yourself
                // in this case, you'd set it to 5
            }   
            return result;
        }
   ...

答案 3 :(得分:0)

首先,您可以声明这样的属性,以便它们受到保护。

public int BaseStat ( get; protected set; }
public int DerivedStat { get; protected set; }

其次,根据所描述的场景,以下可能是更好的属性。或者,如果您不想继续计算它,您可以更新受保护的财产“发货”。以类似的方式。

public int DerivedStat
{
    get
    {
        var derivedStat = 0;
        foreach (var component in components)
        {
            derivedStat += baseStat + 5;
        }

        return derivedStat;
    }
}

答案 4 :(得分:0)

如果我正确地阅读了您的问题,那么您几乎就在那里public int DerivedStat{ get { return derivedStat ; } } - 使用您应该受保护字段的访问者。在这个非常基本的示例中,您可以在set方法中进行一些验证,如下所示。这样,其他类就不会看到ship的内部结构,但是他们可以尝试来修改它。

以下内容如何:

class ship
{
    protected int baseStat = 0;    //I want this to be protected - now it is
    private int derivedStat = 0; //This should also be protected - can even be private
    public int DerivedStat {
        get 
        {
            return derivedStat;
        }
        set
        {
            if(value < 0)
                throw new Exception("Validate your data here!");
            derivedStat = value;
        }
    }
}

答案 5 :(得分:0)

通过A处理的B上的事件......

A可以通过向其集合添加A来注册B事件,并在删除时使用ObservableCollection注销并监视其更改。