对象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;
}
}
为Ship
添加方法,允许其他人修改Ship
,但赋予Ship
确保自身一致性的责任和能力。这意味着
- 外部各方可以请求
Ship
更新,但Ship
可以拒绝这样的请求,如果他们会违反一些约束(或者如果Ship
只是感觉不像被更新的任何原因)。 - 你可以给这些方法命名来传达操作的语义,同时将
Ship
的实现细节与程序的其余部分解耦。您可以自由更改表示Ship
内部状态的方式。
如果你想让每个组件实现决定新统计的算法,你可以
- 使船舶的属性为只读(它们必须对组件进行计算可见)
- 让组件的DeriveStats(…)方法返回计算值
- 使船舶本身调用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并监视其更改来取消注册。