是通过set accessor通过其容器的get访问器为属性赋值是一件坏事吗?

时间:2009-05-12 16:20:54

标签: c# oop properties

请考虑以下代码:

class Program
{
    static void Main(string[] args)
    {
        Department deathStar = new Department { Name = "Death Star" };

        Console.WriteLine("The manager of {0} is {1}.", deathStar.Name, deathStar.Manager.FullName);

        deathStar.Manager.FirstName = "Lord";

        Console.WriteLine("The manager of {0} is {1}.", deathStar.Name, deathStar.Manager.FullName);

        Console.ReadLine();
    }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string FullName
    {
        get
        {
            return this.FirstName + " " + this.LastName;
        }
    }
}

public class Department
{
    public string Name { get; set; }

    public Person Manager { get; private set; }

    public Department()
    {
        this.Manager = new Person { FirstName = "Darth", LastName = "Vader" };
    }
}

产生以下输出:

The manager of Death Star is Darth Vader.
The manager of Death Star is Lord Vader.

即使我不能将Manager更改为Person(私有集访问器)的不同或新实例,我也可以更改它的属性(具有公共集访问器)。

那么,通过set访问器通过其容器的get访问器为属性赋值是一件坏事吗?换句话说,这是代码味道吗?

修改

这只是一个例子来说明一点。仅为此示例创建了人员和部门。

7 个答案:

答案 0 :(得分:2)

没有必要。

例如,查看SqlCommand对象上的参数集合。您可以更改集合中的项目,但不能将新参数集合分配给命令对象。

举个例子,如果你有一个维护Person对象的UI,并且你需要更改一个人的名字,那么改变人名,单独保留姓和PersonId字段,然后更新数据库表就完全有效了。使用PersonId字段。

这对我来说听起来不错

答案 1 :(得分:1)

是的,这是代码味道。

虽然这似乎是一种相当无害的做法,但公共属性会将您的类的字段暴露给任意更改,并且会对实现细节产生不必要的依赖。您也可以使用结构。 (我并不是说结构也不好。程序编程和OOP一样有用。这一切都取决于要解决的问题)封装的目的是隐藏类中的实现细节家属。相反,您应该公开抽象接口,允许依赖类修改内部数据,而无需了解其实现。请考虑以下示例:

public interface Vehicle {
    double FuelTankCapacityInGallons{get;}
    double GallonsOfGasoline{get;}
}

public interface Vehicle {
    double getPercentFuelRemaining();
}

两个接口都可以获得剩余汽油量。第一个通过具体术语,第二个通过抽象。如果油箱的尺寸发生变化或者您需要实施欧洲汽车,那么第一个示例将需要更改车辆和任何正在使用它的车辆。而第二个只需要更改车辆实施。

我使用的例子来自Robert C. Martin的书“清洁代码 - 敏捷软件工艺手册”。

我也会查找Law of Demeter

答案 2 :(得分:0)

我会说那句话:

deathStar.Manager.FirstName = "Lord";

在其意图中非常清楚,所以它不会打扰我。

困扰我的是经理上的私人套装。

这意味着一旦创建了一个部门,它的经理就永远不会被改变。

作为现实的典范,这是一个很大的时间气味。

答案 3 :(得分:0)

这是“坏事”吗?本质上不是。这是否表明您应该重新检查您的课程设计?是。为什么创建Department修改Person对象的内容?您是否应该在ChangeManager上实施Department方法?也许,也许不是。但这是一个值得问的问题。

答案 4 :(得分:0)

只要Person不是结构,这不是问题:如果是,则Manager属性将返回Person的副本,并且您将在该副本上设置FirstName属性,而不是在部门的Manager上。但无论如何,如果你试图这样做,编译器会尖叫......

答案 5 :(得分:0)

这是一个OOP纯度的问题 并非所有代码都应该是纯OOP。这是项目复杂性,涉及的程序员数量,可维护性等问题 你的例子非常简单,这就是为什么你可以阅读这么多意见的原因 有时很难用简单的例子来说明OOP的优点。

无论如何,我的想法:
它闻起来很香 真正困扰我的代码行是

deathStar.Manager.FirstName = "Lord";

它很容易变成像

这样的东西
deathStar.Manager.Address.City.Name = "Paris"

因此,在一行代码中,您会看到正在使用的4个类!这是一个非常强烈的假设,即所有4个类的耦合保持不变。换句话说,它使类保持高度耦合 你可以通过使用接口而不是具体的类来解决这个问题,你可以采用“告诉别问”指南(Yahoo search;是的,雅虎)。
讨论OOP和重构的Here's a nice PDF(在Java中,但很容易理解这些想法),请参阅“传递耦合”部分。

答案 6 :(得分:-1)

我认为这是人们如此大肆宣传功能语言的原因之一 - 没有“副作用”。我不认为这有任何技术上的错误,但它可以使维护非常困难。用Jurrasic Park的话来说,“......只是因为你能做点什么,并不代表你应该做到的!”