我有以下对象(类)。
let trimmed_len = correct_name.trim_right().len();
correct_name.truncate(trimmed_len);
以下类使用上述对象,因此按如下方式初始化对象:
namespace Temp.Models
{
public class CurrentClass
{
private double _firstCoefficient;
private double _secondCoefficient;
public double FirstCoefficient
{
get { return _firstCoefficient; }
set { _firstCoefficient= value; }
}
public double SecondCoefficient
{
get { return _secondCoefficient; }
set { _secondCoefficient= value; }
}
}
}
如果某些条件得到满足,我会按如下方式定义变量:
namespace Temp.Models
{
public class MainClass
{
private CurrentClass _currentClass = new CurrentClass();
public CurrentClass CurrentClass
{
get { return _currentClass; }
set { _currentClass = value; }
}
}
}
但如果条件永远不会满足并且我从未定义上述变量会怎样。检查对象是否从未被定义的最佳方式和/或最佳方法是什么?
我可以进行以下检查:
MainClass currentObject = new MainClass();
//if conditions are met
currentObject.CurrentClass.FirstCoefficient = 0;
currentObject.CurrentClass.SecondCoefficient = 5;
但值可以定义为0 ......所以我不确定如何解决这个问题。
非常感谢任何帮助!
答案 0 :(得分:1)
这些原则可用于解释描述,样本和简要评估/意见的问题。
根据OOP原则,构造函数是用于将对象初始化为有效状态的方法。不变性的概念更进一步,不允许任何变化,完全避免无效状态。
如果对象的API不允许无效状态,也有可能出现妥协。
有了这个概念,你就会到达:
namespace Temp.Models
{
public class CurrentClass
{
public double FirstCoefficient { get; private set; }
public double SecondCoefficient { get; private set; }
public CurrentClass(double firstCoefficient, double secondCoefficient)
{
FirstCoefficient = firstCoefficient;
SecondCoefficient = secondCoefficient;
}
// if mutability is required - this is needless as the constructor is
// the same but if there was more complex state, methods like this would make
// sense, mutating only parts of the state
public void SetCoefficients(double firstCoefficient, double secondCoefficient)
{
FirstCoefficient = firstCoefficient;
SecondCoefficient = secondCoefficient;
}
}
}
要点:
CurrentClass
的每个实例都始终处于有效状态,避免了大量的一致性检查(改进的封装)
编写代码需要更多代码(但由于前一点,您可以保存很多其他代码)
您需要事先了解系数。
Nullable类型添加"额外"对于类型的价值," undefined"州。引用类型(class
)可以设计为可空,而值类型(struct
)需要标记为可为空,可以是Nullable<T>
,也可以是速记T?
。
然后,这允许对象处于无效状态并且对其具体。这是从不变性到另一端的一致性,因为具有多个可空字段的对象具有许多无效状态。
示例代码:
namespace Temp.Models
{
public class CurrentClass
{
public double? FirstCoefficient { get; set; }
public double? SecondCoefficient { get; set; }
}
}
现在这可以很好地实例化,并且可以即时更改:
public CurrentClass CreateCurrentClass()
{
var currentClass = new CurrentClass { FirstCoefficient = 1.0 };
var secondCoefficient = RetrieveSecondCoefficient();
currentClass.SecondCoefficient = secondCoefficient;
return currentClass;
}
但是,您需要在使用对象的任何地方进行有效性检查。
public bool IsValid(CurrentClass currentClass)
{
// what if FirstCoefficient has value and SecondCoefficient doesn't,
// is that always an invalid state?
return currentClass.FirstCoefficient.HasValue
&& currentClass.SecondCoefficient.HasValue;
}
要点:
让DTO启动并运行
使用此类模型需要进行大量的一致性检查(以及相关的脑痛)
缺乏封装 - 任何采用CurrentClass
的方法都可能会改变其有效性,因此使前一点变得更糟。通过使用只需要只读访问权限的只读接口,可以缓解这种情况。
在上述两种方法之间还有许多其他方法。例如,您可以为每个对象使用一个有效性标记(SergeyS&#39; s响应),并简化外部有效性检查,但在课堂上有更多代码,需要更深入思考。
就个人而言,我更喜欢不变性。它可以编写更多的猴子代码,但由于设计简洁,它肯定会得到回报。
没有广泛的知识,没有不可变性的复杂系统很难推理。在团队中工作时尤其痛苦 - 通常每个人只知道代码库的一部分。
令人遗憾的是,并不总是有可能使evertything不可变(例如viewmodels):然后我倾向于尽快将对象转换为内部不可变模型。
答案 1 :(得分:0)
鉴于您已撰写的内容,我会将Initialize()
方法和Initialized
属性添加到您的MainClass
课程中。类似的东西:
public class MainClass
{
private CurrentClass _currentClass = new CurrentClass();
public CurrentClass CurrentClass
{
get { return _currentClass; }
set { _currentClass = value; }
}
public bool Initialized {get; private set;}
public void Initialize()
{
this.CurrentClass.FirstCoefficient = 0;
this.CurrentClass.SecondCoefficient = 5;
this.Initialized = true;
}
}
调用符合条件的Initialize()
方法。
稍后在代码中,您只需检查if(currentObject.Initialized)
即可。注意'Initialized'属性的私有setter,它将确保外部代码不会意外设置此标志。
根据您的需要,您可以进一步将参数初始化直接传递给Initialize()
方法作为参数。
答案 2 :(得分:0)
你有几种方法,比如强制值在构造函数中是正确的,或者有另一个变量告诉对象是否还没有值,比如System.Drawing.Point有静态&#34;空&#34;属性。但是在你的简单对象的情况下,你的主类是显式创建一个CurrentClass的实例,所以此时这个对象应该是正确的,并且应该设置系数。如果您依赖其他一些代码来设置这些值以便稍后执行某些其他操作,则此处超出了这两个对象的范围。
更新:perharps分享真正问题的细节会更好,因为我有一种感觉试图提供一个简化的例子,最终隐藏了真正的问题。