封装与普通

Encapsulation Vs Plain

如果下面的代码会产生相同的结果,我为什么要使用封装?

The main benefit of encapsulation is the ability to modify our implemented code without breaking the code of others who use our code.

但是我可以在不使用封装的情况下使用这个好处,对吗?因为每个物体的场都与彼此的场不同。

// Person.java
public class Person {
  // Plain
  public String name;

  // Uses encapsulation
  private String name2;
  public void setName(String name2) {
    this.name2 = name2;
  }
  public String getName() {
    return name2;
  }
}

// Main.java
public class Main() {
  public static void main(String[] args) {
    // Plain
    Person person = new Person();
    person.name = "Jordan";
    System.out.println(person.name);

    // Uses encapsulation
    Person person2=new Person();
    person2.setName("Jordan");
    System.out.println(person2.getName());
  }
}
  1. 通过提供 getter 和 setter,我们获得了隐藏实现的好处。例如您可以使用惰性初始化、代理等。
  2. 代码变得更易于维护,例如您可以轻松地在一处添加预检查和 post 检查(或验证)。如果您直接访问该变量,之后您需要在读取值时添加任何验证或一些默认行为,您将不得不在多个地方更改它。
  3. 通过 getter 和 setter,您可以获得多态性的好处。例如如果您不想在扩展版本中更改变量的值,反之亦然,您可以简单地抛出异常。

从调试的角度:

  1. 提供访问或更新变量值的代码行的隔离。 (可以用来查参考资料)
  2. 有时候,我们需要知道变量的值在哪里改变了。您可以放置​​调试指针或记录器来调查它。

封装是使 class 中的字段成为私有字段并通过 public 方法提供对字段的访问的技术。

public class Person {

private String name;
private Date dob;
private transient Integer age;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Date getDob() {
    return dob;
}

public void setDob(Date dob) {
    this.dob = dob;
}

public int getAge() {
    if (age == null) {
        Calendar dob_cal = Calendar.getInstance();
        dob_cal.setTime(dob);
        Calendar today = Calendar.getInstance();
        age = today.get(Calendar.YEAR) - dob_cal.get(Calendar.YEAR);
        if (today.get(Calendar.MONTH) < dob_cal.get(Calendar.MONTH)) {
            age--;
        } else if (today.get(Calendar.MONTH) == dob_cal.get(Calendar.MONTH)
                && today.get(Calendar.DAY_OF_MONTH) < dob_cal.get(Calendar.DAY_OF_MONTH)) {
            age--;
        }
    }
    return age;
  }
}

方法getAge()returns你这个人的年龄,你不需要关心它是如何实现的,你不需要计算class之外的年龄。

使用封装的一种方法是隐藏实现。例如,有时 getter 不是 getter。考虑像球体这样的形状,我不一定会将体积或表面积存储为变量,因为我可以随时计算它们。我仍然会调用成员函数 getVolume 和 getSurfaceArea。使用我的代码的人不需要知道我是计算值还是简单地存储值。通过公开我的变量,我将它们锁定在一个设计决策中,如果我改变我的实现,这个设计决策将不得不改变(或破坏)。通过隐藏实现,您只需要知道接口(不要与 Java 的 'interface' 混淆)它以这种方式保护每个人并使未来的更改变得更加容易。

需要注意的是,有些时候setters/getter没有用到,变量就暴露了。即使在 Java 中,有时不隐藏实例变量更有意义。

你的问题很有意思。我会尽力为您深入解答。

封装背后的主要思想是对其他用户隐藏数据及其实现细节。如果我们将一个数据成员设为 private,那么它只能在同一个 class 中访问。没有其他 class 可以直接访问该数据。

但是我们可以定义一个接口,即 public getter 和 setter 方法来更新来自其他 classes 的数据。这可确保 私有数据对其他人保持无法访问 ,并且只能通过您提供的 public 方法访问。

例如,您可能决定只为特定数据成员提供 getter 方法而不提供 setter 方法。这确保没有其他 class 可以以任何可能的方式更改或更新您的数据成员。如果他们想使用 getter 方法,他们只能获得该值。

这就是封装也被称为数据隐藏的原因。

例子

public class EncapsulationDemo{
    private int ssn;
    private String empName;
    private int empAge;

    //Getter and Setter methods
    public int getEmpSSN(){
        return ssn;
    }

    public String getEmpName(){
        return empName;
    }

    public int getEmpAge(){
        return empAge;
    }

    public void setEmpAge(int newValue){
        empAge = newValue;
    }

    public void setEmpName(String newValue){
        empName = newValue;
    }

    public void setEmpSSN(int newValue){
        ssn = newValue;
    }
}
public class EncapsTest{
    public static void main(String args[]){
         EncapsulationDemo obj = new EncapsulationDemo();
         obj.setEmpName("Mario");
         obj.setEmpAge(32);
         obj.setEmpSSN(112233);
         System.out.println("Employee Name: " + obj.getEmpName());
         System.out.println("Employee SSN: " + obj.getEmpSSN());
         System.out.println("Employee Age: " + obj.getEmpAge());
    } 
}

优势

1) 它为代码提供 灵活性 并使其 易于维护。 我们可以更改 getEmpName() 的实现或 setEmpName() 而不影响任何其他外部代码。

2) 我们可以使数据成员只读(通过只定义getters)或只写 (通过仅定义 setters)随时。

3) 其他用户不会知道幕后发生的事情。他们只会知道要更新数据,我们需要调用 setter 方法,要获取数据,我们需要调用 getter 方法。