In "Normal
“(这并不“正常”),这是完全合法的代码:
public static void main(String args[]) {
Normal normal = new Normal();
normal.name = "suhail gupta";
System.out.println( "My name is : " + normal.name );
}
现在你的界面includes a String
称为的值name
。用户希望能够使用 VarName.name 或 VarName.setName 语法来设置它。用户希望能够使用 VarName.name 或 VarName.getName 检索它;
例如,这在“Normal
":
public static void main(String args[]) {
Normal normal = new Normal();
normal.name = null;
String name = normal.name;
System.out.println( "My name is : " + name );
}
现在,也许你会想“那又怎样?”想象一下,如果将变量设置为 null 与实际打印(发生错误的地方)相隔 30 个文件。很难知道是谁搞砸了该变量的值。还有nothing您可以采取措施防止用户搞砸。
现在,如果你已经实现了setName
像这样:
public String setName(String newName) {
assert newName;
name = newName ;
return name ;
}
然后,就会出现错误立即地当用户做错事时。用户尝试将一个不允许为空的值设置为空,因此会出现错误。您有一个调用堆栈,显示错误发生的位置,这更容易调试。
当然,这没有帮助,因为“的用户Normal
“ 才不是have to use setName
。他们可以自由地戳name
直接地。
虽然从技术上讲它可能是封装,但就我而言,如果用户可以轻松且简单地破坏它,那么它就不是封装。如果没有保护,就没有封装。
当他们说 Unencapsulated 意味着 Unchangeable 时,它怎么在这里是不可更改的呢?
好吧,假设你给我一个包含以下内容的库Normal
。我会以某种方式使用它。也许我有Normal
实例分散在 50 个文件中。他们all直接设置并获取名称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();
}
}
少了什么东西?public String name;
该功能不再可用,因为您现在有了名字和姓氏。请注意,两个访问器方法没有改变at all.
当我升级到您的库的新版本时,您将只需破坏了我所有的代码。我不希望我的代码仅仅因为您决定更改类中数据的存储方式而被破坏。我现在再也不会使用你制作的任何东西,因为你甚至无法保持界面从一个版本到下一个版本的一致性。
如果你做得正确的话,这一切都不会发生。