-6

你会如何回答这个面试问题?

以下内容有什么风险,您如何重写它以使其更安全?

class Line {public Point p1; public Point p2; public double length;}

谢谢,

4

3 回答 3

3

如果意图是让长度成员提供线的长度,那么风险是可以更改长度而不考虑点之间的“真实”距离。

有很多方法可以解决这个问题。这是一个:

class Line {
  public Point p1;
  public Point p2;
  public double length {
     get {
        return ....
     }
  }
}

这样,每次访问时都会计算距离并且它是只读的,因此可以防止引入不一致的更改

于 2013-06-14T18:22:30.207 回答
1
  1. 首先,您没有在类上设置显式修饰符,因此您最终会得到默认值(如果它在命名空间中internal或者private如果包含在一个类中)。这可能会在编译时造成轻微的不便。一个更大的问题可能是,如果默认值暴露了超出预期的类,在这种情况下,您可能会不知不觉地允许对类的访问超出预期。在任何情况下,初学者或中等 C# 程序员都很难看到这一点并知道会发生什么,这可能是一个可维护性问题。

  2. 但是,最大的问题是您的所有类字段都被声明为公共的。通常,您希望使用属性来公开字段:限制读/写能力,通过反射使字段更容易被发现,执行验证等。这导致...

  3. 你可以看到这个类被命名为“Line”并且暴露了它的点和长度。调用者当前可以轻松更改任何这些值,但不会更新其他值。考虑到更改长度会产生不可预测的结果(哪一点会改变?),长度可能应该是计算属性(只读)。

    所以我会把这个类重写为:

    public class Line
    {
        public Point P1 {get;set;}
        public Point P2 {get;set;}
        public double Length
        {
            get
            {
                return Math.Sqrt( 
                    Math.Pow( P2.X - P1.X, 2 ) + 
                    Math.Pow( P2.Y - P1.Y, 2 ) 
                );
            }
        }
    }
    
  4. 如果有多个线程一起工作,甚至在两个对象引用同一个 Line 实例并且一个对象可能不知道另一个对象的更改(从而导致问题)的简单情况下,此类的可变性可能会导致问题。如果可变性是一个问题,那么所有属性都应该是只读的:

    public class Line
    {
        private Point _p1;
        public Point P1
        {
            get
            {
                return _p1;
            }
        }
        private Point _p2;
        public Point P2
        {
            get
            {
                return _p2;
            }
        }
        private double _length;
        public double Length
        {
            get
            {
                return _length;
            }
        }
    
        public Line(Point p1, Point p2)
        {
            _p1 = p1;
            _p2 = p2;
            _length = Math.Sqrt( 
                    Math.Pow( _p2.X - _p1.X, 2 ) + 
                    Math.Pow( _p2.Y - _p1.Y, 2 ) 
                );
        }
    
    }
    
于 2013-06-14T18:26:29.520 回答
1

所有成员都应该是属性获取器/设置器。支持成员/字段将是可选的。
Length 属性是个例外。您不希望 Length 修改独立于 Line 特性 - 例如,不考虑点坐标使属性只读。

class Line {
   private Point _startPoint;
   private Point _endPoint;

   public double Length {
      get { return _startPoint.X - _endPoint.X; } // modify for your own algorithm
   }

   // add public property setters for Start and End Points
}

这可以防止最终开发人员或消费应用程序修改长度而不受线坐标的影响。

注意:
一行似乎是一个值类型,可能是一个结构。

于 2013-06-14T18:31:01.997 回答