android設計模式二十三式(十七)——責任鏈模式(Chain of Responsibility)

責任鏈模式

閱讀過handler源碼的同學,可能還有印象,handler的message存在隊列中是以鏈式結構存在的,所以,這裏,我們的責任鏈模式,核心就是一個鏈式的結構。

當一個對象持有對下一個對象的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。但是發出者並不清楚到底最終哪個對象會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。

我們還是舉一個現實的例子:現在孩子上學,要有學籍才行,當我們先去找學校,學校說要教育局辦學籍,去到教育局,說要派出所的戶口本,去到派出所,說要醫院的出生證明,於是去到醫院拿到了出生證明,再回到派出所辦理戶口本,再去教育局辦理學籍。這樣就是一個從上至下再回來的一個完整的處理。

我們來看一下代碼

抽象一個類,所有組織的父類,在父類方法operation中對事件進行處理,子類正常情況下不應複寫此類。

/**
 * @author: hx
 * @Time: 2019/5/22
 * @Description: Org
 */
public abstract class Org {
    private String name;
    private Org next;

    public Org(String name) {
        this.name = name;
    }

    public Org setNext(Org next) {
        this.next = next;
        return next;
    }

    /**
     * 執行操作
     */
    public boolean operation(Parents parents){
        if (solve(parents)){
            System.out.println("---"+name + "能處理此問題");
            return true;
        }else if (next != null){
            System.out.println("---"+name + "不能處理此問題,下一級處理");
            if (next.operation(parents)) {
                System.out.println("---"+name + "的下一級處理成功,本級再次處理");
                solve(parents);
                return true;
            }else {
                System.out.println("---"+name + "的下一級處理失敗");
                failed(parents);
            }
            return false;
        }else {
            System.out.println("---"+name+ "已經是最後一級");
            failed(parents);
            return false;
        }
    }

    /**
     * 處理操作
     * @param parents
     */
    protected abstract boolean solve(Parents parents);

    /**
     *
     * @param parents
     * @return
     */
    protected abstract void failed(Parents parents);


}

再寫一個有個要上學的孩子的父母類,包含出生日期,出生證明,戶口本,學籍這些關鍵的字段。

/**
 * @author: hx
 * @Time: 2019/5/22
 * @Description: Parents
 */
public class Parents {
    private String birthCertificate;
    private String householdRegister;
    private String studentProof;
    private String birthday;

    public String getBirthCertificate() {
        return birthCertificate;
    }

    public void setBirthCertificate(String birthCertificate) {
        this.birthCertificate = birthCertificate;
    }

    public String getHouseholdRegister() {
        return householdRegister;
    }

    public void setHouseholdRegister(String householdRegister) {
        this.householdRegister = householdRegister;
    }

    public String getStudentProof() {
        return studentProof;
    }

    public void setStudentProof(String studentProof) {
        this.studentProof = studentProof;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }
}

下面就是集成org組織的子類實現了,學校,教育局,派出所,醫院。

/**
 * @author: hx
 * @Time: 2019/5/22
 * @Description: School
 */
public class School extends Org {

    public School() {
        this("學校");
    }

    public School(String name) {
        super(name);
    }

    @Override
    protected boolean solve(Parents parents) {
        if (parents.getStudentProof()!= null){
            System.out.println("有學籍證明,可以入學");
            return true;
        }else{
            System.out.println("沒有學籍證明,需要去教育局辦理");
            return false;
        }
    }

    @Override
    protected void failed(Parents parents) {
        System.out.println("失敗-沒有學籍證明,教育局不給辦理");
    }
}

/**
 * @author: hx
 * @Time: 2019/5/22
 * @Description: EducationBureau
 */
public class EducationBureau extends Org {

    public EducationBureau() {
        this("教育局");
    }

    public EducationBureau(String name) {
        super(name);
    }

    @Override
    protected boolean solve(Parents parents) {
        if (parents.getHouseholdRegister() != null){
            parents.setStudentProof("學籍");
            System.out.println("有戶口本,可以辦理學籍");
            return true;
        }else {
            System.out.println("沒有戶口本,需派出所辦理");
            return false;
        }
    }

    @Override
    protected void failed(Parents parents) {
        System.out.println("失敗-沒有戶口本,派出所辦不給辦理");
    }
}

/**
 * @author: hx
 * @Time: 2019/5/22
 * @Description: PoliceStation
 */
public class PoliceStation extends Org {

    public PoliceStation() {
        this("派出所");
    }

    public PoliceStation(String name) {
        super(name);
    }

    @Override
    protected boolean solve(Parents parents) {
        if (parents.getBirthCertificate() != null){
            parents.setHouseholdRegister("戶口本");
            System.out.println("有出生證明,辦理戶口本");
            return true;
        }else {
            System.out.println("沒有出生證明,需醫院開證明");
            return false;
        }
    }

    @Override
    protected void failed(Parents parents) {
        System.out.println("失敗-沒有出生證明,醫院不給開證明");
    }
}

/**
 * @author: hx
 * @Time: 2019/5/22
 * @Description: Hospital
 */
public class Hospital extends Org {

    public Hospital() {
        this("醫院");
    }

    public Hospital(String name) {
        super(name);
    }

    @Override
    protected boolean solve(Parents parents) {
        if (parents.getBirthday() != null){
            parents.setBirthCertificate("出生證明");
            System.out.println("沒有出生證明,開一個出生證明");
            return true;
        }else{
            System.out.println("不知道出生日期,不給開出生證明");
            return false;
        }
    }

    @Override
    protected void failed(Parents parents) {
        System.out.println("失敗-醫院不給開出生證明");
    }
}

先來一個有出生日期的父母

public static void main(String[] args){
    Parents parents = new Parents();
    parents.setBirthday("1-1");

    School school = new School();
    EducationBureau educationBureau = new EducationBureau();
    PoliceStation policeStation = new PoliceStation();
    Hospital hospital = new Hospital();
    school.setNext(educationBureau).setNext(policeStation).setNext(hospital);
    school.operation(parents);
}

輸出結果:
沒有學籍證明,需要去教育局辦理
---學校不能處理此問題,下一級處理
沒有戶口本,需派出所辦理
---教育局不能處理此問題,下一級處理
沒有出生證明,需醫院開證明
---派出所不能處理此問題,下一級處理
沒有出生證明,開一個出生證明
---醫院能處理此問題
---派出所的下一級處理成功,本級再次處理
有出生證明,辦理戶口本
---教育局的下一級處理成功,本級再次處理
有戶口本,可以辦理學籍
---學校的下一級處理成功,本級再次處理
有學籍證明,可以入學

再來看一個孩子沒有出生日期的父母

public static void main(String[] args){
    Parents parents = new Parents();

    School school = new School();
    EducationBureau educationBureau = new EducationBureau();
    PoliceStation policeStation = new PoliceStation();
    Hospital hospital = new Hospital();
    school.setNext(educationBureau).setNext(policeStation).setNext(hospital);
    school.operation(parents);
}

輸出結果:
沒有學籍證明,需要去教育局辦理
---學校不能處理此問題,下一級處理
沒有戶口本,需派出所辦理
---教育局不能處理此問題,下一級處理
沒有出生證明,需醫院開證明
---派出所不能處理此問題,下一級處理
不知道出生日期,不給開出生證明
---醫院已經是最後一級
失敗-醫院不給開出生證明
---派出所的下一級處理失敗
失敗-沒有出生證明,醫院不給開證明
---教育局的下一級處理失敗
失敗-沒有戶口本,派出所辦不給辦理
---學校的下一級處理失敗
失敗-沒有學籍證明,教育局不給辦理

這樣我們就可以看到,以及以及來處理,每一級的處理都只關聯到下一級,除了知道下一級之外,對其他的對想都毫無所知。

熟悉的同學可能發現,這個非常像android中事件的處理機制。沒錯,android中的事件處理的確也是這樣的,只不過android中的事件處理其阿里,比我們這裏的簡答的demo要複雜一些,處理了很多不同類型的事件,也有攔截的功能,有興趣的同學可以瞭解一下android的事件傳遞機制。

鏈式的結構可以是一條鏈,可以是一個樹,還可以是一個環,模式是不約束這個的,只要自己去實現就行,但是,在一個時刻,只能由一個對象傳給另一個對象處理,不能同時傳給多個對象來處理。

事件的開始,我們只交給第一個對象來處理,至於後面誰來處理的,我們就不關心了,解耦事件最終處理和請求處理的人之間的關係,如果不採用這種方法,那請求處理的人,就必須知道所有的環節的功能,這在現實中其實基本是不可能的。

責任鏈模式,還可以動態的修改事件處理順序,擁有非常良好的擴展性,處理環節之間,也是解耦的,只關心自己的部分。

但是,因爲處理事件在鏈上傳遞,需要一個一個的尋找,需要花費一定的時間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章