public class Normal {
public string name; // name is public
public String getName() {
return name ;
}
public String setName(String newName) {
name = newName ;
return name ;
}
public static void main(String args[]) {
Normal normal = new Normal();
normal.setName("suhail gupta");
System.out.println( "My name is : " + normal.getName() );
}
}
新课程从这里开始
public class Different {
private string name; // name is private
public String getName() {
return name ;
}
public String setName(String newName) {
name = newName ;
return name ;
}
public static void main(String args[]) {
Different different = new Different();
different.setName("suhail gupta");
System.out.println( "My name is : " + different.getName() );
}
}
第一类将 name 声明为public,其他类的名称声明为 private 。这两个类都做同样的工作,但只有名称不同的访问说明符。现在,
我的问题是?
private
优先于public
? (我已完成相同的工作,声明名称公开,因为我已声明private
) refactoring
期间,哪些班级程序员会放心?normal
类与 different
类有什么不同?答案 0 :(得分:5)
在“Normal
”中(没有什么“正常”),这是完全合法的代码:
public static void main(String args[]) {
Normal normal = new Normal();
normal.name = "suhail gupta";
System.out.println( "My name is : " + normal.name );
}
您的界面现在包含名为String
的{{1}}值。用户希望能够使用VarName.name或VarName.setName语法进行设置。用户希望能够使用VarName.name或VarName.getName;
例如,这在“name
”中是合法的:
Normal
现在,也许你会想到“那么什么?”想象一下,如果将变量设置为null,则将实际打印(发生错误的位置)与30个文件分开。很难知道谁搞砸了那个变量的价值。 可以阻止用户搞砸它。
现在,如果你已经实现了public static void main(String args[]) {
Normal normal = new Normal();
normal.name = null;
String name = normal.name;
System.out.println( "My name is : " + name );
}
:
setName
然后,当用户做错事时,错误会立即发生 。用户尝试将值设置为null,不允许为null,因此出错。你有一个调用堆栈,显示错误发生的位置,这更容易调试。
当然,这没有用,因为“public String setName(String newName) {
assert newName;
name = newName ;
return name ;
}
”的用户不必须使用Normal
。他们可以直接在setName
戳戳。
虽然技术上可能是封装,但就我而言,如果用户可以轻松而轻易地破坏它,那么它就不是封装。如果没有保护,就没有封装。
当他们说Unencapsulated意味着不可改变时,它是如何在这里不变的?
好吧,假设你给我一个包含name
的图书馆。我将以某种方式使用它。也许我有Normal
个实例分散在50个文件中。他们所有直接设置并获取Normal
而不是访问者的名称。这是完全合法的,因为你做了name
。
现在,无论出于何种原因,您决定不希望将名称存储在字符串中。也许你需要能够拥有名字和姓氏。所以,让我们说你的库的下一个版本有这个定义:
public
缺少什么? public class Normal
{
public string firstName;
public string lastName;
public String getName()
{
return firstName + " " + lastName;
}
public String setName(String newName)
{
//parse newName into a first and last name.
...
firstName = newFirstName;
lastName = newLastName;
return getName();
}
}
那已经不再可用了,因为你现在拥有名字和姓氏。请注意,两个访问器方法并未完全更改 。
当我升级到新版本的库时,您只需打破我的所有代码。我不喜欢我的代码被破坏只是因为你决定改变你在课堂上存储数据的方式。我现在再也不会使用你做的任何东西了,因为你甚至不能保持你的界面从一个版本到下一个版本的一致。
如果你刚刚做好了事情,那都不会发生。
答案 1 :(得分:3)
getter和setter的想法是允许开发人员执行其他所需的逻辑来派生类字段的值。因此,将类字段保留为公共允许在为该字段分配值之前跳过执行逻辑。
第二个类更容易维护,因为可以确定name变量的值总是通过setter设置。
同样,第二类更适合重新分解,因为它暴露的成员较少。
如果您想象其他开发人员使用“普通”类,他可以选择直接设置name的值,而不是使用setter。因此,如果将来您决定更改“名称”变量的可见性,您将打破其他人员代码。在这样一个简单的例子中,这并不重要,但是在编写重要代码时,这往往会成为问题,因为您不希望通过更改变量的可见性来破坏其他开发人员代码。因此,封装的代码不可更改。
一般来说,更好的设计往往会暴露较少的运动部件。但是除了封装之外,还可以缩小其他代码可以操纵类内部的方式。
答案 2 :(得分:0)
Different
是一个比Normal
更好的封装示例,尽管有一些简单的东西,其好处并不明显。
Different
理论上更容易维护,因为如果您想要更改name
的内部表示,则无需修改公共API即可。
与#2相同,原因相同。
虽然第一个类允许用户直接修改name
,但第二个类允许用户通过getName()
和setName()
。
如果某些东西未被封装,你就会向世界展示所有细节内在的细节。追溯更改很难(如果不是不可能),因为您将破坏使用它的任何现有代码。