# 封裝

> 介紹封裝的概念。

物件導向最基本的原則，把真實世界的某個事物包成物件，裡面的資訊不對外公開，只公開某些特定方法讓別人使用，內部的實做及資料都隱藏起來，不讓人直接使用，也不需要讓別人直接使用。也就是所謂的 資訊隱藏（Information Hiding）

設想一個例子，

提款機，你不知道它裡面還有多少錢，也不知道內部的運做，不知道哪家公司生產的機器，但你還是會去使用他提供的方法：查詢餘額、提款。 因為他只開放這兩個方法給一般人使用，你要使用這兩個方法需要帶入的參數是提款卡及密碼，就可以完成你的需求。

```java
class 提款機{
    private int 剩餘現金;
    private boolean 身分確認(提款卡、密碼){
        ...
    }
    private void 吐鈔(){
        ...
    }
    public void 提款(提款卡、密碼){
        if(身分確認(提款卡、密碼) == true)
            吐鈔();
    }
    public void 查詢餘額(提款卡、密碼){
        ...
    }
}
```

當然實際上更為複雜且嚴密(而且我對提款機不熟)，但在怎麼複雜，使用上一般使用者只要知道使用哪些公開的方法就好(雖然不熟但我會領錢、查餘額)，剩下的就是設計這個類別的設計師要負責的工作。

## 常用修飾子 private 、 public

### private 私有

private是資訊隱藏會普遍使用的修飾子，開放全限最低，只有自己類別的成員能夠存取。

### public 公開

與private相反，public是任何人都可以調用，通常用來表示這個方法可以供一般人呼叫，一個public的方法內可以呼叫多個private的方法來實作需要的功能。

> 其他修飾子請參考『存取修飾子』章節。

物件導向是將『資料及其方法』包裝成物件，而資料、方法的劃分都是設計師決定的，但要記得物件的核心是資料，而不是方法。 (data是主角)

封裝的概念是將資訊隱藏，只透過某些公開的方法讓外界存取使用。

## Getter、Setter

為了資訊隱藏，我們常把重要資料設為private，要供別人(甚至自己)存取的時候，通常會利用getter()及setter()這種透過公開方法間接的存取。

來看個例子，學生的類別有姓名年齡3個欄位，提供兩個setter兩個getter：

```java
class Student{
    private String firstName;
    private String lastName;
    private int age = -1;

    public void setName(String first,String last){
        if( first == null || last == null || first.length()==0 || last.length()==0 ){
            System.out.println("ERROR: name輸入錯誤，名字姓氏不得為空");
        }else{
            firstName = first;
            lastName = last;
        }
    }
    public void setAge(int a){
        if(a < 0){
            System.out.println("ERROR: age輸入錯誤，年齡不可能為負數");
        }else{
            age = a;
        }
    }
    public String getName(){
        if( firstName==null || lastName==null)
            return "unset";
        else
            return firstName + lastName;
    }
    public int getAge(){
        return age;
    }
}// end of class Student
```

這是常見的設計方法，資料成員的部份我都設為private，而公開了setName(.)及setAge(.)讓別人呼叫來設定name及age的值，這就是透過公開方法間接的設定隱藏的欄位，好處是我這樣寫可以在設定欄位前先做一些前處理(以上述程式來說就是檢查參數的合法性)。

在getter的部份，也公開了兩個方法可以讓別人存取到內部隱藏的成員，以getName()來說，可以在回傳出去前多做一步處理(這裡是把名跟姓串起來)，這樣的設計方式是常見且容易維護的。

測試程式：

```java
class Test {
    public static void main(String[] args) {

        Student s1 = new Student();
        s1.setName("小木","");
        s1.setAge(-500);
        System.out.println(s1.getName());
        System.out.println(s1.getAge());

        Student s2 = new Student();
        s2.setName("Tina", "Lee");
        s2.setAge(18);
        System.out.println(s2.getName());
        System.out.println(s2.getAge());

    }// end of main(String[])
}// end of class Test
```

執行結果：

```java
ERROR: name輸入錯誤，名字姓氏不得為空
ERROR: age輸入錯誤，年齡不可能為負數
unset
-1
TinaLee
18
```

可以看到物件s1因為亂帶參數，所以用setter在設定前被先檢查出來，可以進一步增加程式的穩定性。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yubin551.gitbook.io/java-note/object_oriented_programming/encapsulation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
