C#基础制作属性原子

时间:2009-09-11 23:03:25

标签: c# design-patterns

Microsoft已将其作为框架设计指南,properties应该彼此独立,而不是依赖于按任何特定顺序设置。

假设您有一个需要支持dimmensions和面积计算的三角形类。你会如何模仿这个?

这当然是被认为是gauche的设计,因为Area依赖于Base和Height首先设置:

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

您仍然拥有一个依赖于其他属性的属性。为了成为一个纯粹主义者,我只能看到几种方法(我想它们可以结合起来):

  1. Make Base / Height具有只能在构造函数中设置的只读成员

  2. 将面积计算成方法。

  3. 使用某种工厂模式+ readonly成员来确保尽管可能存在依赖关系,但只能通过实例化Triangle类的方法来设置值。

  4. 问题:

    1. 指南是否切实可行(为了支持它,您是否必须在类中建立很多复杂性)? [例如,SqlConnection类允许您初始化连接字符串属性,但允许您更改它的各个部分,例如命令超时]

    2. 如何管理保持您的财产彼此独立?

    3. 对于使用Silverlight / MVVM类型体系结构的人来说,由于数据绑定对象的工作方式,您是否接受属性中的依赖项?例如,绑定一个在屏幕上显示高度,基数和面积的三角形实例。

5 个答案:

答案 0 :(得分:15)

微软真的试图说“不要以这样一种方式设计你的类,即以任意顺序调用属性会导致意外行为。”您班级的用户不希望请求值(使用属性)产生尴尬的副作用。

这属于最不意外的原则。

我认为这是一个完全实用的指南。属性不应该有意想不到的副作用。

你提出了一个很好的问题:“你如何管理保持你的财产彼此独立?”。非常小心!我尽可能地消除状态(并相应地减少属性的数量)。此外,通过分解类来分区状态是另一种策略。这本身就是一个很好的问题......

就三角形类而言,我认为您在代码中呈现的两种解决方案都是有效的。如果由我决定,我会设计三角形以使其不可变,并在构造函数中获取宽度和高度。

答案 1 :(得分:3)

最简单的方法是仅在构造函数上接受base和height值,然后将它们作为只读属性公开:

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

答案 2 :(得分:2)

我想我会选择一个Triangle类,它有一个构造函数,它带有Base&高度作为参数,因为三角形不能存在(imho)没有基础或高度。

Offcourse,Area属性依赖于Base&身高,但我觉得这没问题? 我认为MS指南应解释如下:

  

属性应该独立于   彼此而不依赖于存在   按任何特定顺序设置。

含义-imho-您不应该首先必须设置Base属性,并且只有在设置了Base属性后才能设置Height属性。 我认为这就是上述指南的意思。

接下来,您的Area属性不可设置,因此没有问题。 :)

答案 3 :(得分:0)

某些属性本质上是相关的和相关的。关键是首先设置基础,然后高度应该与设置高度相同,然后是基础。没有设置其中一个,那么检查该区域是没有意义的。

答案 4 :(得分:0)

选择选项2.将区域设为方法并将其命名为CalculateArea。属性应该用于封装状态而不是行为。该区域可以从基数和高度计算并不意味着它本身应该是状态;相反,这是一个强有力的论据,即Area应该成为州。

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

这让消费者知道,获取三角形区域需要真正的工作,而不是简单地访问状态。