请考虑以下代码:
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访问器为属性赋值是一件坏事吗?换句话说,这是代码味道吗?
修改
这只是一个例子来说明一点。仅为此示例创建了人员和部门。
答案 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的话来说,“......只是因为你能做点什么,并不代表你应该做到的!”