Berbagi teknologi

Pola Desain Pola Rantai Tanggung Jawab

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Konsep

Pola Rantai Tanggung Jawab: Hindari menggabungkan pengirim dan penerima permintaan, berikan kesempatan kepada banyak objek untuk menerima permintaan, hubungkan objek-objek ini ke dalam sebuah rantai, dan teruskan permintaan di sepanjang rantai ini hingga ada objek yang menanganinya.Model rantai tanggung jawab adalah apola perilaku objek

2. Struktur

Inti dari struktur pola rantai tanggung jawab adalah pengenalan aprosesor abstrak
Masukkan deskripsi gambar di sini

Terlihat dari gambar, diagram struktur pola rantai tanggung jawab memuat dua peran sebagai berikut:
(1) Handler (penanganan abstrak): Ini mendefinisikan antarmuka untuk memproses permintaan dan umumnya dirancang sebagai kelas abstrak. Karena penangan beton yang berbeda menangani permintaan secara berbeda, metode penanganan permintaan abstrak didefinisikan di dalamnya.Karena bawahan masing-masing prosesor masih berupa prosesor, objek bertipe prosesor abstrak (penerus dalam diagram struktur) didefinisikan dalam prosesor abstrak sebagai bawahannya.Mengutip . Melalui referensi ini, penangan dapat dihubungkan menjadi sebuah rantai.
(2) ConcreteHandler (penanganan beton): Ini adalah subkelas dari penangan abstrak dan dapat menangani permintaan pengguna.Metode pemrosesan permintaan abstrak yang ditentukan dalam prosesor abstrak diimplementasikan di kelas prosesor konkret, dan dapat mengakses objek berikutnya dalam rantai untuk mencapaiPermintaan penerusanMemengaruhi.
Pada pola Chain of Responsibility, setiap referensi objek terhadap turunannya dihubungkan membentuk suatu rantai. Permintaan diteruskan ke rantai ini hingga objek mana dalam rantai tersebut akhirnya menangani permintaan tersebut. Hal ini memungkinkan sistem untuk mengatur ulang rantai secara dinamis dan menetapkan tanggung jawab tanpa memengaruhi klien.

3.Kode tipikal

Inti dari pola rantai tanggung jawab terletak pada desain kelas penangan abstrak. Kode khas kelas penangan abstrak adalah sebagai berikut:

abstract class Handler {
    //维持对下家的引用
    protected Handler successor;
    
    public void setSuccessor(Handler successor) {
        this.successor = successor;    
    }
    
    public abstract void handleRequest(String request);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Dalam kode di atas, pemroses abstrak mendefinisikan objek referensi ke pemroses berikutnya untuk meneruskan permintaan ke pemroses berikutnya. Pengakses objek ini dapat diatur ke dilindungi, yang dapat digunakan dalam subkelasnya.

Penangan beton adalah subkelas dari penangan abstrak dan memiliki dua fungsi utama:

  • Untuk memproses permintaan, prosesor spesifik yang berbeda mengimplementasikan metode pemrosesan permintaan abstrak handleRequest() dalam bentuk berbeda;
  • Meneruskan permintaan. Jika permintaan melebihi jangkauan pemrosesan prosesor saat ini, permintaan dapat diteruskan ke prosesor berikutnya.

Kode tipikal untuk kelas handler tertentu adalah sebagai berikut:

class ConcreteHandler extends Handler {
    public void handleRequest(String request) {
        if (请求满足条件) {
            //处理请求        
        } 
        else {
            this.successor.handleRequest(request);  //转发请求
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4. Studi Kasus 1: Sistem Persetujuan Pesanan Pembelian

Sistem persetujuan pesanan pembelian tertentu bersifat hierarkis, yaitu disetujui oleh supervisor di berbagai tingkatan sesuai dengan jumlah pembelian.

Direktur dapat menyetujui pesanan pembelian kurang dari 50.000 yuan, wakil ketua dapat menyetujui pesanan pembelian sebesar [5, 100.000 yuan], ketua dewan dapat menyetujui pesanan pembelian sebesar [10, 500.000 yuan], dan pesanan pembelian sebesar 500.000 yuan dan di atasnya. Rapat dewan diperlukan untuk membahas dan memutuskan.
Masukkan deskripsi gambar di sini

Karena pemberi persetujuan setiap posisi mempunyai bawahan (kecuali dewan direksi), dan perilaku mereka adalah hal yang umum, mereka semua melibatkan penyampaian persetujuan kepada penerusnya. Jadi rancang kelas pemberi persetujuan sebagai pemroses abstrak:

//审批者类: 抽象处理者
abstract class Approver {
    protected Approver successor;  //定义后继对象
    protected String name;  //审批者姓名

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

    //设置后继者
    public void setSuccessor(Approver successor) {
        this.successor = successor;
    }

    public abstract void processRequest(PurchaseRequest request);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Kemudian setiap posisi, sebagai pemroses tertentu, harus mengimplementasikan pemroses abstrak:

//主任: 具体处理者
class Director extends Approver{
    public Director(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 50000) {
            System.out.println(
                    MessageFormat.format("主任 {0} 审批采购单:{1}, 金额:{2}元, 采购目的:{3}。",
                            this.name, request.getNumber(), request.getAmount(), request.getPurpose())
            );
        } else {
            this.successor.processRequest(request);  //转发请求
        }
    }
}

//副董事长:具体处理类
class VicePresident extends Approver{
    public VicePresident(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 100000) {
            System.out.println(
                    MessageFormat.format("副董事长 {0} 审批采购单:{1}, 金额:{2}元, 采购目的:{3}。",
                            this.name, request.getNumber(), request.getAmount(), request.getPurpose())
            );
        } else {
            this.successor.processRequest(request);
        }
    }
}

//董事长类:具体处理者
class President extends Approver{
    public President(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 500000) {
            System.out.println(
                    MessageFormat.format("董事长 {0} 审批采购单:{1}, 金额:{2}元, 采购目的:{3}。",
                            this.name, request.getNumber(), request.getAmount(), request.getPurpose())
            );
        } else {
            this.successor.processRequest(request);
        }
    }
}

//董事会类:具体处理者
class Congress extends Approver{
    public Congress(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        System.out.println(
                MessageFormat.format("召开董事会 审批采购单:{0}, 金额:{1}元, 采购目的:{2}。",
                        request.getNumber(), request.getAmount(), request.getPurpose())
        );
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

Tentukan kategori pesanan pembelian lain sebagai target yang perlu disetujui:

//采购单: 请求类
class PurchaseRequest {
    private double amount;  //采购金额
    private int number;  //采购单编号
    private String purpose;  //采购目的

    public PurchaseRequest(double amount, int number, String purpose) {
        this.amount = amount;
        this.number = number;
        this.purpose = purpose;
    }

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public String getPurpose() {
        return purpose;
    }

    public void setPurpose(String purpose) {
        this.purpose = purpose;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

Tulis kode pengujian klien:

class Client {
    public static void main(String[] args) {
        Approver kangXi, yongZheng, qianLong, hanLinYuan;
        kangXi = new Director("康熙");
        yongZheng = new VicePresident("雍正");
        qianLong = new VicePresident("乾隆");
        hanLinYuan = new Congress("翰林院");

        //创建职责链
        kangXi.setSuccessor(yongZheng);
        yongZheng.setSuccessor(qianLong);
        qianLong.setSuccessor(hanLinYuan);

        //创建采购单
        PurchaseRequest pr1 = new PurchaseRequest(45000, 10001, "购买刀");
        kangXi.processRequest(pr1);

        PurchaseRequest pr2 = new PurchaseRequest(60000, 10002, "购买枪");
        kangXi.processRequest(pr2);

        PurchaseRequest pr3 = new PurchaseRequest(160000, 10003, "购买火炮");
        kangXi.processRequest(pr3);

        PurchaseRequest pr4 = new PurchaseRequest(800000, 10004, "购买军舰");
        kangXi.processRequest(pr4);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

Kompilasi dan jalankan program, outputnya adalah sebagai berikut:

主任 康熙 审批采购单:10,001, 金额:45,000元, 采购目的:购买刀。
副董事长 雍正 审批采购单:10,002, 金额:60,000元, 采购目的:购买枪。
董事长 乾隆 审批采购单:10,003, 金额:160,000元, 采购目的:购买火炮。
召开董事会 审批采购单:10,004, 金额:800,000元, 采购目的:购买军舰。
  • 1
  • 2
  • 3
  • 4

5. Analisis Kasus 2: Pengolahan Tugas Kelas

Mari kita rancang kasus yang sedikit berbeda dari kasus di atas, yang dapat memperluas pemahaman kita tentang model rantai tanggung jawab dan skenario penerapannya.

  • Perbedaan pertama: metode permintaan handler memiliki nilai kembalian dan dapat memberi umpan balik informasi ke host;
  • Perbedaan kedua: kasus "Sistem Persetujuan Pesanan Pembelian" memproses permintaan terlebih dahulu dan kemudian meneruskan permintaan tersebut, sedangkan kasus "Pemrosesan Tugas Kelas" meneruskan permintaan terlebih dahulu dan kemudian memproses permintaan tersebut.

Sekolah akan memberikan beberapa tugas kepada kelas untuk diproses. Jenis ini termasuk satu, dua, tiga, empat, dan seterusnya. Guru kelas dapat menangani tiga jenis tugas satu, dua, tiga, dan pengawas dapat menangani dua jenis tugas tersebut. satu, dua. Tugas, komite pembelajaran dapat menangani salah satu dari jenis tugas ini. Ketika guru kelas menerima tugas, dia akan menyerahkannya terlebih dahulu kepada ketua regu untuk diproses, jika kelas berikutnya tidak dapat menanganinya, maka guru kelas akan menanganinya sendiri. Ketika guru kelas menerima tugas, dia akan menyerahkannya terlebih dahulu menyerahkan kepada komite sekolah untuk diproses. Jika kelas berikutnya tidak dapat menanganinya, guru kelas akan menanganinya sendiri. Ketua regu akan menanganinya sendiri, jika komite sekolah menerima tugas, dia akan menanganinya sendiri; Dan ketika mereka tidak bisa mengatasinya, mereka akan memberikan feedback ke atas.

Kelas Handler dirancang di bawah ini sebagai prosesor abstrak:
Karena Anda dan bawahan Anda belum tentu dapat menangani tugas kelas tertentu dan terdapat umpan balik ke atas, metode permintaan prosesor harus memiliki nilai kembalian boolean untuk memberi tahu atasan apakah metode tersebut dapat menangani tugas tersebut.

abstract class Handler {
    protected Handler successor;  //定义后继对象

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract boolean handleRequest(String taskName);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Di bawah ini, guru kelas, ketua regu, dan anggota komite belajar masing-masing dirancang sebagai penangan khusus.
Secara default, guru kelas akan memberikan tugas kepada ketua regu terlebih dahulu, dan ketua regu akan memberikan tugas kepada anggota komite belajar secara default. Anggota komite belajar hanya dapat menangani satu jenis tugas, dan jika tidak dapat menanganinya , itu akan mengembalikan false;
Jika umpan balik yang diterima oleh pemimpin regu salah, dia akan menanganinya sendiri. Dia hanya dapat menangani satu atau dua jenis tugas. Jika dia tidak dapat menanganinya, dia akan mengembalikan kesalahan;
Jika umpan balik yang diterima kepala sekolah salah, dia akan menanganinya sendiri. Dia hanya bisa menangani tugas satu, dua, dan tiga jenis. Jika dia tidak bisa menangani tugas itu, dia akan mengembalikan yang salah.

//班主任
class HeadTeacher extends Handler{
    @Override
    public boolean handleRequest(String taskName) {
        boolean handled = successor.handleRequest(taskName);
        if (handled) {
            return true;
        }
        if (taskName.equals("one") || taskName.equals("two") || taskName.equals("three")) {
            System.out.println("班主任处理了该事务");
            return true;
        }

        return false;
    }
}

//班长
class Monitor extends Handler{
    @Override
    public boolean handleRequest(String taskName) {
        boolean handled = successor.handleRequest(taskName);
        if (handled) {
            return true;
        }
        if (taskName.equals("one") || taskName.equals("two")) {
            System.out.println("班长处理了该事务");
            return true;
        }

        return false;
    }
}

//学习委员
class StudyCommissary extends Handler{
    @Override
    public boolean handleRequest(String taskName) {
        boolean handled;
        if (successor == null) {  //注意学习委员可能没有下家,所以这里判一下是否为空
            handled = false;
        } else {
            handled = successor.handleRequest(taskName);
        }

        if (handled) {
            return true;
        }
        if (taskName.equals("one")) {
            System.out.println("学习委员处理了该事务");
            return true;
        }

        return false;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

Tulis kode pengujian klien:
Siapkan sub-house untuk setiap posisi, namun perhatikan bahwa tidak ada sub-house untuk anggota komite studi.
Selain itu, jika ada tugas yang tidak dapat ditangani oleh kepala sekolah, cetaklah sebaris catatan untuk menjelaskannya.

public class SchoolClient {
    public static void main(String[] args) {
        Handler headTeacher, monitor, studyCommissary;
        headTeacher = new HeadTeacher();
        monitor = new Monitor();
        studyCommissary = new StudyCommissary();

        headTeacher.setSuccessor(monitor);
        monitor.setSuccessor(studyCommissary);
        studyCommissary.setSuccessor(null);  //没有下一职责人

        startRequest(headTeacher, "one");
        startRequest(headTeacher, "two");
        startRequest(headTeacher, "three");
        startRequest(headTeacher, "four");
    }

    private static void startRequest(Handler headTeacher, String taskName) {
        if (! headTeacher.handleRequest(taskName)) {
            System.out.println("该班级处理不了此类任务!");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Kompilasi dan jalankan program, outputnya adalah sebagai berikut:

学习委员处理了该事务
班长处理了该事务
班主任处理了该事务
该班级处理不了此类任务!
  • 1
  • 2
  • 3
  • 4

6. Skenario yang berlaku

Model Rantai Tanggung Jawab dapat dipertimbangkan dalam situasi berikut:

  • Ada beberapa objek yang dapat menangani permintaan yang sama. Objek spesifik yang menangani permintaan tersebut akan ditentukan pada saat runtime.Klien hanya perlu mengirimkan permintaan ke rantai tanpa mempedulikan oleh siapa permintaan tersebut diproses dan bagaimana permintaan tersebut diproses.
  • Kirimkan permintaan ke salah satu dari beberapa objek tanpa menentukan penerima secara eksplisit
  • Sekumpulan objek dapat ditentukan secara dinamis untuk menangani permintaan.Klien dapat secara dinamis membuat rantai tanggung jawab untuk menangani permintaan, dan juga dapat mengubah urutan antar pemroses dalam rantai tersebut.


Buku referensi:
"Seni Pola Desain" - Liu Wei