C#使属性原子化的基础知识
它是由微软提供的一个框架设计指南,应该相互独立,不依赖于以任何特定顺序设置 假设您有一个三角形类,它需要支持调光和面积计算。您将如何对此进行建模 这当然是被认为是笨拙的设计,因为面积取决于首先设置的基础和高度:C#使属性原子化的基础知识,c#,design-patterns,C#,Design Patterns,它是由微软提供的一个框架设计指南,应该相互独立,不依赖于以任何特定顺序设置 假设您有一个三角形类,它需要支持调光和面积计算。您将如何对此进行建模 这当然是被认为是笨拙的设计,因为面积取决于首先设置的基础和高度: class Triangle{ public double Base {get;set;} public double Height {get;set;} public double Area { get{ return (
class Triangle{
public double Base {get;set;}
public double Height {get;set;}
public double Area {
get{
return (Base * Height) / 2;
}
}
}
假设您使用构造函数,您可以确保这种情况下的默认值,但这是正确的方法吗
class Triangle{
public Triangle(double b, double h){
Base = b;
Height = h;
}
public double Base {get;set;}
public double Height {get;set;}
public double Area {
get{
return (Base * Height) / 2;
}
}
}
您仍然有一个依赖于其他属性的属性。为了成为一名纯粹主义者,我只能看到几种方法(我想它们可以结合使用):
Microsoft实际上是在试图说“不要以这样的方式设计类:以任意顺序调用属性将导致意外行为”。您的类的用户不希望请求值(使用属性)会产生尴尬的副作用 这符合最不出人意料的原则 我认为这是一个完全实用的指导方针。属性不应有意外的副作用 你提出了一个很好的问题:“你如何使你的财产彼此独立?”。非常小心!我尽可能地消除状态(并相应地减少属性的数量)。另外,通过划分类来划分状态也是一种策略。这本身就是一个很好的问题
就三角形类而言,我认为您在代码中提供的两种解决方案都是有效的。如果由我决定,我会设计三角形,使其不可变,并在构造函数中采用宽度和高度。最简单的方法是只在构造函数中接受底部和高度值,然后将它们全部作为只读属性公开:
class Triangle
{
private double base;
private double height;
private Triangle() { }
public Triangle(double base, double height)
{
this.base = base;
this.height = height;
}
public double Base
{
get
{
return this.base;
}
}
public double Height
{
get
{
return this.height;
}
}
public double Area
{
get
{
return (this.base * this.height) / 2;
}
}
}
我想我会选择一个三角形类,它有一个构造函数,它以底和高度为参数,因为没有底或高度,三角形就不可能存在(imho) 当然,Area属性依赖于Base&Height,但我认为这没有问题? 我认为MS指南应解释如下: 属性应该独立于 彼此之间不依赖存在 按任何特定顺序设置 这意味着-imho-您不应该有一个必须首先设置基本属性的约束,并且只有在设置了基本属性之后,您才能设置高度属性。
我认为这就是上述指引的意思
除此之外,您的Area属性是不可设置的,因此它没有问题。:) 某些属性将具有内在的相关性和相互依赖性。重点是,先设置“基础”,然后设置“高度”,应该与先设置“高度”,然后设置“基础”具有相同的效果。如果不设置其中一个,则检查该区域将没有意义。选择选项2。将Area设置为一个方法,并将其称为CalculateArea。属性应该用来封装状态,而不是行为。面积可以从底部和高度计算,但这并不意味着它本身应该是状态;相反,这是一个强有力的论点,即该地区不应是国家
class Triangle
{
public Triangle(double b, double h)
{
Base = b;
Height = h;
}
public double Base { get; set; }
public double Height { get; set; }
public double CalculateArea()
{
return (Base * Height) / 2;
}
}
这让消费者知道,获取三角形区域需要实际工作,而不是简单地访问状态。为什么要将它们公开为只读?那么,你不能改变三角形。。。当然,如果您将三角形视为一种值类型(因此是不可变的),那么您就有了一个点,但是在本例中是否有必要将三角形视为一种值类型。。。我认为话题发起人刚刚错误地解释了指南。:)除非你有令人信服的理由不这样做,否则一定要使对象不可变。三角形就是一个很好的例子——你到底为什么要改变它而不是创建一个新的呢?这并不是说可变对象一开始很可怕,而是将一个对象放入多线程场景中,突然之间,除了“三角形”对象的程序员决定使用setter进行编程外,你没有什么好的理由需要同步。你不能使用base作为变量名,它是一个关键字。它也不能是参数名和类变量名