对象A有对象B的列表,对象B修改类A的适当方式

本文关键字:对象 方式 列表 修改 | 更新日期: 2023-09-27 18:16:27

我已经尽了最大的努力去研究这个问题,但是我一直没有找到一个好的答案。很可能是因为我不知道该怎么问这个问题。所以我要把所有的东西都扔出去。

这是我的两个类的基本结构。(显然不是实际代码)

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;
    }
}

这一切都工作得很好,我有许多不同类型的组件子类做不同的事情的船和它的统计,但有了这个设置,所有的统计是可见的和可修改的船类之外。从设计角度来看,这似乎是不正确的,坦率地说,这让我发疯了。

是否有更干净/更正确的方法来处理这个问题?

编辑-

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

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;
    }
}

对象A有对象B的列表,对象B修改类A的适当方式

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

  1. 外部各方可以请求Ship更新,但Ship可以拒绝这样的请求,如果他们会违反一些约束(或者如果Ship只是感觉不像被更新的任何原因)。
  2. 你可以给这些方法命名来传达操作的语义,同时将Ship的实现细节与程序的其余部分解耦。您可以自由更改表示Ship内部状态的方式。
编辑:

如果你想让每个组件实现决定新统计的算法,你可以

  1. 使船舶的属性为只读(它们必须对组件进行计算可见)
  2. 让组件的DeriveStats(…)方法返回计算值
  3. 使船舶本身调用DeriveStats(…)并相应地更新其值。

这有一个额外的好处,即船舶负责汇总来自不同组件的结果。由于组件彼此不了解,他们如何协调谁来决定飞船的状态?

我有两个办法

组件应该计算东西(在你的例子中是统计)并返回它。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);
    }
}

首先,你可以像这样声明你的属性,使它们受到保护。

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

其次,根据所描述的场景,以下属性可能更适合您。或者,如果你不想让它连续计算,你可以用类似的方式从'Ship'中更新受保护的属性。

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

如果我正确地阅读了您的问题,您几乎有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;
        }
    }
}

你可以使用属性来保持相同的基础属性,并根据它的组件计算船的有效属性。

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;
        }
   ...

A处理B上的Via事件…

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