天天看點

封裝的好處--筆記

以下筆記摘自《java核心技術卷1》

以下給出了一個薪金管理系統的一部分代碼

package Employee;

import java.time.LocalDate;

public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay;
    public Employee(String name, double salary, int year,int month,int day) {
        this.name = name;
        this.salary = salary;
        this.hireDay = LocalDate.of(year,month,day);
    }

    public String getName() {
        return name;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public LocalDate getHireDay() {
        return hireDay;
    }

    public void setHireDay(LocalDate hireDay) {
        this.hireDay = hireDay;
    }
    public void raiseSalary(double byPercent) {
        double raise=salary*byPercent/100;
        salary+=raise;
    }
}

package Employee;

public class EmployeeTest {
    public static void main(String[] args) {
        Employee[] staff = new Employee[3];
        staff[0] = new Employee("Carl",75000,1987,12,15);
        staff[1]=new Employee("Harry",50000,1989,10,1);
        staff[2]=new Employee("Tony",40000,1990,3,15);
        for(Employee e : staff)
            e.raiseSalary(5);
        for(Employee e : staff)
            System.out.println("name="+e.getName()+",salary="+e.getSalary()+",hireDay="+e.getHireDay());
    }
}
           

 封裝的優點

關鍵字private確定隻有Employee類自身的方法能夠通路這些執行個體域,而其它類的方法不能夠讀寫這些域。

public String getName() {
    return name;
}      

是典型的通路器方法。

将name、salary和hireDay域标記為public,以此來取代獨立的通路器方法會不會更容易些呢?

name是一個隻讀域。一旦在構造器中設定完畢,就沒有任何一個辦法可以對他進行修改,這樣來確定name域不會受到外界的破壞。

雖然salary不是隻讀域,但是它隻能用raiseSalary方法進行修改,一旦這個域值出現了錯誤,隻要調試這個方法就可以了。如果salary域是public的,破壞這個域值的搗亂者有可能會出現在任何地方,

有些時候,需要獲得或設定執行個體域的值,應提供以下三種内容:

  • 一個私有的資料域
  • 一個共有的域通路器方法
  • 一個公有的域更改器方法

這樣做要比提供一個簡單的共有資料域複雜些,但是卻有着下列明顯的好處:

1、首先,可以改變内部實作,除了該類的方法之外,不會影響其他代碼。

     例如:如果将存儲名字的域改為:

     String firstName;

     String lastName; 

     那麼,getName方法可以改為傳回

     fisrtName+""+lastName

    對于這點改變,程式的其他部分完全不可見。

2、為了進行新舊資料表示之間的轉換,通路其方法和更改器方法有可能需要做許多工作。但是,浙江為我們帶來了第二點好處:更改器方法可以執行錯誤檢查,然而直接對域進行指派将不會進行這些處理。例如setSalary方法可以檢查新近是否小于0。

注意:不要編寫“傳回可變引用對象”的通路器方法!

現在假如把Employ類中的

private LocalDate hireDay;部分改為private Date hireDay;就會出問題。      

LocalDate類沒有更改器方法,與之不同,Date類有一個更改器方法setTime,可以在這裡設定毫秒數。

Date對象是可變的,這一點就破壞了封裝性。

假如有人寫

Employee harry=...;
Date d=harry.getHireDay();
double tenYearsInMilliSeconds=10*365.25*24*60*60*1000;
d.setTime(d.getTime()-(long)tenYearsInMilliSeconds);      

那麼,d和harry.hireDay引用同一個對象,對d調用更改器方法可以自動的改變這個雇員對象的私有狀态。