接上次博客:二十四種設(shè)計(jì)模式與六大設(shè)計(jì)原則(二):【門(mén)面模式、適配器模式、模板方法模式、建造者模式、橋梁模式、命令模式】的定義、舉例說(shuō)明、核心思想、適用場(chǎng)景和優(yōu)缺點(diǎn)-CSDN博客
目錄
裝飾模式【Decorator Pattern】
定義
舉例說(shuō)明
核心思想
適用場(chǎng)景
優(yōu)缺點(diǎn)
迭代器模式【Iterator Pattern】
定義
舉例說(shuō)明
核心思想
適用場(chǎng)景
優(yōu)缺點(diǎn)
組合模式【Composite Pattern】?
定義
舉例說(shuō)明
核心思想
適用場(chǎng)景
優(yōu)缺點(diǎn)
觀察者模式【Observer Pattern】
定義
舉例說(shuō)明
核心思想
適用場(chǎng)景
優(yōu)缺點(diǎn)
責(zé)任鏈模式【Chain of Responsibility Pattern】
定義
舉例說(shuō)明
核心思想
適用場(chǎng)景
優(yōu)缺點(diǎn)
訪問(wèn)者模式【Visitor Pattern】?
定義
舉例說(shuō)明
核心思想
適用場(chǎng)景
優(yōu)缺點(diǎn)
?
裝飾模式【Decorator Pattern】
定義
裝飾器模式(Decorator Pattern)是一種結(jié)構(gòu)型設(shè)計(jì)模式,允許在不改變對(duì)象自身結(jié)構(gòu)的情況下,動(dòng)態(tài)地給對(duì)象添加額外的功能。它通過(guò)將對(duì)象封裝在一個(gè)或多個(gè)裝飾器中,從而使得客戶端可以根據(jù)需要透明地、逐層地包裝對(duì)象。
裝飾器模式 允許向現(xiàn)有對(duì)象添加新功能而不改變其結(jié)構(gòu)。這種類(lèi)型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它允許向現(xiàn)有類(lèi)添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種模式創(chuàng)建了一個(gè)裝飾器類(lèi),用來(lái)包裝原有的類(lèi),并在不改變?cè)蓄?lèi)結(jié)構(gòu)的前提下,添加了新的功能或責(zé)任。
在裝飾器模式中,有如下幾個(gè)角色:
-
組件接口(Component):定義了具體組件和裝飾器需要實(shí)現(xiàn)的接口或抽象類(lèi)。它是被裝飾的對(duì)象的公共接口,可以是抽象類(lèi)或接口。
-
具體組件(Concrete Component):實(shí)現(xiàn)了組件接口,并定義了基本行為。
-
裝飾器(Decorator):實(shí)現(xiàn)了組件接口,并包含一個(gè)組件對(duì)象,它可以通過(guò)該對(duì)象實(shí)現(xiàn)對(duì)原有組件的功能擴(kuò)展。通常它會(huì)維護(hù)一個(gè)指向組件對(duì)象的引用,并在調(diào)用原始對(duì)象的基本操作之前或之后執(zhí)行附加的操作。
-
具體裝飾器(Concrete Decorator):實(shí)現(xiàn)了裝飾器接口,并擴(kuò)展了被裝飾對(duì)象的行為。
裝飾器模式的關(guān)鍵優(yōu)勢(shì)在于它提供了一種靈活的方式來(lái)擴(kuò)展類(lèi)的功能,而無(wú)需使用子類(lèi)繼承。這樣可以避免創(chuàng)建大量的子類(lèi),使得類(lèi)的結(jié)構(gòu)更加靈活,并且符合開(kāi)閉原則。
舉例說(shuō)明
假設(shè)你是一位咖啡愛(ài)好者,經(jīng)常去一家咖啡館喝咖啡。這家咖啡館提供了各種口味的咖啡,包括美式咖啡、拿鐵、卡布奇諾等。你發(fā)現(xiàn)雖然咖啡館提供了豐富的選擇,但有時(shí)候你想要的口味并不在標(biāo)準(zhǔn)菜單上。于是你想到了一個(gè)主意:為什么不給每種咖啡添加額外的口味,以滿足自己更多的口味需求呢?
在這個(gè)場(chǎng)景中,咖啡可以被看作是被裝飾的對(duì)象,而不同口味的添加則可以被看作是裝飾器。例如,你可以選擇在美式咖啡中添加焦糖味、香草味或榛果味等。這樣,你可以根據(jù)自己的口味喜好,動(dòng)態(tài)地給咖啡添加不同的口味,而不需要咖啡館專(zhuān)門(mén)提供每種口味的單獨(dú)菜單。
具體來(lái)說(shuō),假設(shè)你點(diǎn)了一杯拿鐵咖啡,但你想要讓這杯拿鐵咖啡更加豐富一點(diǎn),你可以選擇添加巧克力口味或是焦糖口味。在這里,拿鐵咖啡就是被裝飾的對(duì)象,而巧克力口味和焦糖口味就是裝飾器。通過(guò)裝飾器,你可以在不改變拿鐵咖啡本身的情況下,為其添加額外的口味,從而讓咖啡味道更加層次豐富。
// 咖啡接口
interface Coffee {
String getDescription();
double cost();
}
// 具體咖啡類(lèi):拿鐵
class Latte implements Coffee {
@Override
public String getDescription() {
return "拿鐵咖啡";
}
@Override
public double cost() {
return 15.0;
}
}
// 裝飾器:口味裝飾器
abstract class FlavorDecorator implements Coffee {
protected Coffee coffee;
public FlavorDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public String getDescription() {
return coffee.getDescription();
}
@Override
public double cost() {
return coffee.cost();
}
}
// 具體裝飾器:巧克力口味
class ChocolateFlavor extends FlavorDecorator {
public ChocolateFlavor(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + " + 巧克力口味";
}
@Override
public double cost() {
return coffee.cost() + 5.0; // 巧克力口味額外收費(fèi)5元
}
}
// 具體裝飾器:焦糖口味
class CaramelFlavor extends FlavorDecorator {
public CaramelFlavor(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + " + 焦糖口味";
}
@Override
public double cost() {
return coffee.cost() + 3.0; // 焦糖口味額外收費(fèi)3元
}
}
// 客戶端代碼
public class CoffeeShop {
public static void main(String[] args) {
// 原始訂單:拿鐵咖啡
Coffee order = new Latte();
System.out.println("原始訂單:" + order.getDescription() + ",價(jià)格:" + order.cost() + "元");
// 在拿鐵咖啡中添加巧克力口味
order = new ChocolateFlavor(order);
System.out.println("添加巧克力口味后:" + order.getDescription() + ",價(jià)格:" + order.cost() + "元");
// 在拿鐵咖啡中再添加焦糖口味
order = new CaramelFlavor(order);
System.out.println("再添加焦糖口味后:" + order.getDescription() + ",價(jià)格:" + order.cost() + "元");
}
}
這個(gè)例子中的裝飾模式體現(xiàn)在動(dòng)態(tài)地給咖啡添加額外的口味,而不需要修改咖啡本身的結(jié)構(gòu)。這種方式使得你可以根據(jù)自己的口味需求,靈活地定制咖啡的口味,同時(shí)也讓咖啡館的菜單更加簡(jiǎn)潔明了。
核心思想
裝飾器模式的核心思想是在不改變現(xiàn)有對(duì)象結(jié)構(gòu)的情況下,動(dòng)態(tài)地給對(duì)象添加額外的功能。這一模式通過(guò)創(chuàng)建一個(gè)包裝對(duì)象,即裝飾器,來(lái)實(shí)現(xiàn)功能的動(dòng)態(tài)增加。
其核心思想可以總結(jié)如下:
-
組件抽象化:定義一個(gè)抽象組件接口,描述了被裝飾對(duì)象和裝飾器共同的行為,確保它們可以互相替代。
-
裝飾器封裝:創(chuàng)建裝飾器類(lèi),實(shí)現(xiàn)組件接口,并在內(nèi)部維護(hù)一個(gè)指向具體組件對(duì)象的引用。裝飾器可以通過(guò)組合的方式包裝具體組件,并在其基礎(chǔ)上添加額外的功能。
-
透明性:保持裝飾器和具體組件的透明性,即客戶端無(wú)需知道裝飾器和具體組件的具體實(shí)現(xiàn)細(xì)節(jié),可以統(tǒng)一對(duì)待。
-
遞歸組合:裝飾器可以遞歸地嵌套組合,從而實(shí)現(xiàn)對(duì)對(duì)象功能的多層次擴(kuò)展。這使得在運(yùn)行時(shí)動(dòng)態(tài)地添加或刪除功能成為可能。
-
開(kāi)閉原則:通過(guò)裝飾器模式,可以實(shí)現(xiàn)對(duì)現(xiàn)有代碼的功能擴(kuò)展,而無(wú)需修改原有代碼,從而符合開(kāi)閉原則。
總之,裝飾器模式允許動(dòng)態(tài)地給對(duì)象添加功能,同時(shí)保持對(duì)象結(jié)構(gòu)的穩(wěn)定,使得功能的增加和變化變得更加靈活和可控。
適用場(chǎng)景
裝飾器模式通常在以下情況下適用:
-
需要?jiǎng)討B(tài)地給對(duì)象添加額外的功能:裝飾器模式允許在運(yùn)行時(shí)動(dòng)態(tài)地給對(duì)象添加功能,而不影響其結(jié)構(gòu)。這在需要根據(jù)不同需求動(dòng)態(tài)地增加或刪除對(duì)象功能時(shí)非常有用。
-
避免使用子類(lèi)進(jìn)行功能擴(kuò)展:通過(guò)繼承會(huì)導(dǎo)致類(lèi)的爆炸性增長(zhǎng),而裝飾器模式通過(guò)組合的方式避免了這種問(wèn)題,使得功能的增加更加靈活。
-
需要擴(kuò)展或修改現(xiàn)有對(duì)象的功能,但又不希望修改其代碼:裝飾器模式允許在不修改現(xiàn)有代碼的情況下,通過(guò)添加裝飾器來(lái)擴(kuò)展或修改對(duì)象的功能,符合開(kāi)閉原則。
-
需要在不影響其他對(duì)象的情況下對(duì)對(duì)象進(jìn)行功能增強(qiáng):裝飾器模式通過(guò)獨(dú)立的裝飾器類(lèi)對(duì)對(duì)象進(jìn)行包裝,使得對(duì)象的功能增強(qiáng)不會(huì)影響其他對(duì)象,從而保持了系統(tǒng)的靈活性和可維護(hù)性。
-
需要在不同情況下組合和使用對(duì)象的不同功能組合:裝飾器模式允許根據(jù)不同需求動(dòng)態(tài)地組合和使用對(duì)象的不同功能,從而實(shí)現(xiàn)更加靈活和可定制的功能組合。
裝飾器模式適用于需要?jiǎng)討B(tài)地給對(duì)象添加功能,同時(shí)又希望保持對(duì)象結(jié)構(gòu)穩(wěn)定的情況下,以及需要在不修改現(xiàn)有代碼的情況下擴(kuò)展或修改對(duì)象功能的場(chǎng)景。
優(yōu)缺點(diǎn)
裝飾器模式的優(yōu)點(diǎn)包括:
-
動(dòng)態(tài)添加功能:裝飾器模式允許在運(yùn)行時(shí)動(dòng)態(tài)地給對(duì)象添加新的功能,而無(wú)需修改其原始類(lèi)的代碼,使得功能的擴(kuò)展變得靈活方便。
-
避免類(lèi)爆炸:通過(guò)裝飾器模式,可以避免使用大量子類(lèi)來(lái)實(shí)現(xiàn)不同的功能組合,從而避免了類(lèi)的爆炸性增長(zhǎng)。
-
符合開(kāi)閉原則:裝飾器模式通過(guò)組合的方式擴(kuò)展對(duì)象的功能,而不是通過(guò)繼承,符合開(kāi)閉原則,即對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。
-
單一職責(zé)原則:每個(gè)裝飾器類(lèi)只關(guān)注于一個(gè)特定的功能擴(kuò)展,使得類(lèi)更加簡(jiǎn)潔、高內(nèi)聚。
-
靈活性:可以根據(jù)需求任意組合和排列各種裝飾器,以實(shí)現(xiàn)不同的功能組合,從而滿足不同客戶的需求。
裝飾器模式的缺點(diǎn)包括:
-
增加了對(duì)象數(shù)量:每個(gè)裝飾器都會(huì)增加一個(gè)對(duì)象,可能會(huì)導(dǎo)致系統(tǒng)中對(duì)象的數(shù)量增加,增加了系統(tǒng)的復(fù)雜度。
-
可能產(chǎn)生過(guò)多小對(duì)象:如果使用過(guò)多的裝飾器進(jìn)行功能擴(kuò)展,可能會(huì)產(chǎn)生大量的小對(duì)象,增加了系統(tǒng)的內(nèi)存消耗和運(yùn)行開(kāi)銷(xiāo)。
-
容易出錯(cuò):由于裝飾器模式允許動(dòng)態(tài)地給對(duì)象添加功能,但不影響其結(jié)構(gòu),因此在設(shè)計(jì)和使用過(guò)程中容易出錯(cuò),需要謹(jǐn)慎設(shè)計(jì)和管理。
綜上所述,裝飾器模式適用于需要?jiǎng)討B(tài)地給對(duì)象添加功能,同時(shí)又希望保持對(duì)象結(jié)構(gòu)穩(wěn)定的情況下,但在使用過(guò)程中需要注意控制裝飾器的數(shù)量,避免引入過(guò)多的復(fù)雜性。
迭代器模式【Iterator Pattern】
定義
迭代器模式(Iterator Pattern)是一種行為設(shè)計(jì)模式,它允許在不暴露集合底層表示的情況下順序訪問(wèn)集合中的元素。迭代器模式提供了一種方法來(lái)遍歷一個(gè)聚合對(duì)象中各個(gè)元素,而不暴露該對(duì)象的內(nèi)部結(jié)構(gòu)。
具體來(lái)說(shuō),迭代器模式包含兩個(gè)核心角色:迭代器(Iterator)和聚合對(duì)象(Aggregate)。
-
迭代器(Iterator):迭代器是一個(gè)接口,它定義了在集合對(duì)象上遍歷元素的方法,包括獲取下一個(gè)元素、判斷是否還有元素、重置迭代器等。
-
聚合對(duì)象(Aggregate):聚合對(duì)象是一個(gè)接口,它定義了創(chuàng)建相應(yīng)迭代器對(duì)象的方法。聚合對(duì)象可能是一個(gè)集合,例如列表、數(shù)組、樹(shù)等,也可能是一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
迭代器模式的關(guān)鍵思想是將遍歷集合的責(zé)任委托給迭代器對(duì)象,而不是將遍歷邏輯硬編碼在聚合對(duì)象中。這樣做的好處是,可以更容易地實(shí)現(xiàn)不同類(lèi)型的迭代器以適應(yīng)不同類(lèi)型的聚合對(duì)象,同時(shí)將遍歷邏輯與集合的具體實(shí)現(xiàn)解耦,提高了代碼的靈活性和可維護(hù)性。
總之,迭代器模式允許通過(guò)統(tǒng)一的接口來(lái)訪問(wèn)不同類(lèi)型的集合,使得客戶端代碼可以更加簡(jiǎn)潔地遍歷集合中的元素,同時(shí)提供了一種方法來(lái)隱藏集合的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。
舉例說(shuō)明
假設(shè)你是一位圖書(shū)館管理員,需要管理圖書(shū)館中的各種書(shū)籍。你決定設(shè)計(jì)一個(gè)簡(jiǎn)單的圖書(shū)管理系統(tǒng),其中包括圖書(shū)館的書(shū)籍存儲(chǔ)和檢索功能。為了實(shí)現(xiàn)這一目標(biāo),你考慮使用迭代器模式來(lái)管理圖書(shū)館中的書(shū)籍集合。
在這個(gè)圖書(shū)館管理系統(tǒng)中,你有以下角色和元素:
-
書(shū)籍類(lèi)(Book):代表圖書(shū)館中的一本書(shū),包括書(shū)名、作者和出版日期等屬性。
-
書(shū)架類(lèi)(Bookshelf):代表圖書(shū)館中的書(shū)架,用于存放書(shū)籍。書(shū)架內(nèi)部維護(hù)一個(gè)書(shū)籍列表,并提供了添加、刪除和獲取書(shū)籍的方法。
-
迭代器接口(Iterator):定義了迭代器的基本操作,如遍歷下一個(gè)元素、判斷是否還有下一個(gè)元素等。
-
具體迭代器類(lèi)(BookIterator):實(shí)現(xiàn)了迭代器接口,用于遍歷書(shū)架中的書(shū)籍列表。
在這個(gè)系統(tǒng)中,迭代器模式的核心思想是將書(shū)籍集合(書(shū)架)和遍歷算法(迭代器)分離開(kāi)來(lái),使得你可以通過(guò)迭代器來(lái)訪問(wèn)書(shū)架中的書(shū)籍,而無(wú)需關(guān)心書(shū)架內(nèi)部的具體實(shí)現(xiàn)。
舉個(gè)例子,假設(shè)你有一個(gè)書(shū)架,上面擺放了幾本書(shū),包括《Java編程入門(mén)》、《Python實(shí)戰(zhàn)指南》和《C++從入門(mén)到精通》。你可以使用迭代器模式來(lái)遍歷這些書(shū)籍,并進(jìn)行檢索、借閱等操作,而無(wú)需直接操作書(shū)架內(nèi)部的書(shū)籍列表。
通過(guò)這樣的設(shè)計(jì),你可以更加靈活地管理圖書(shū)館中的書(shū)籍,并且可以輕松地?cái)U(kuò)展系統(tǒng),例如添加新的書(shū)籍類(lèi)型或修改遍歷算法,而不會(huì)影響到已有的代碼邏輯。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
// 書(shū)籍類(lèi)
class Book {
private String title;
private String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", author='" + author + '\'' +
'}';
}
}
// 書(shū)架類(lèi)
class Bookshelf implements Iterable<Book> {
private List<Book> books;
public Bookshelf() {
this.books = new ArrayList<>();
}
public void addBook(Book book) {
books.add(book);
}
public void removeBook(Book book) {
books.remove(book);
}
@Override
public Iterator<Book> iterator() {
return new BookIterator();
}
// 具體迭代器類(lèi)
private class BookIterator implements Iterator<Book> {
private int index;
@Override
public boolean hasNext() {
return index < books.size();
}
@Override
public Book next() {
if (hasNext()) {
return books.get(index++);
}
throw new IndexOutOfBoundsException("No more books in the shelf.");
}
}
}
public class LibrarySystem {
public static void main(String[] args) {
// 創(chuàng)建書(shū)架
Bookshelf bookshelf = new Bookshelf();
// 向書(shū)架添加書(shū)籍
bookshelf.addBook(new Book("Java編程入門(mén)", "張三"));
bookshelf.addBook(new Book("Python實(shí)戰(zhàn)指南", "李四"));
bookshelf.addBook(new Book("C++從入門(mén)到精通", "王五"));
// 使用迭代器遍歷書(shū)架中的書(shū)籍并打印
Iterator<Book> iterator = bookshelf.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
核心思想
迭代器模式的核心思想是將遍歷集合的責(zé)任從集合對(duì)象中分離出來(lái),將其封裝在一個(gè)單獨(dú)的迭代器對(duì)象中。這樣,客戶端就可以通過(guò)迭代器對(duì)象逐個(gè)訪問(wèn)集合中的元素,而不必了解集合內(nèi)部的結(jié)構(gòu)和實(shí)現(xiàn)細(xì)節(jié)。
迭代器模式包含以下關(guān)鍵思想:
-
分離集合和遍歷邏輯:迭代器模式將集合的遍歷操作從集合對(duì)象中抽離出來(lái),放置在一個(gè)獨(dú)立的迭代器對(duì)象中。這樣一來(lái),客戶端就可以通過(guò)迭代器對(duì)象來(lái)訪問(wèn)集合元素,而無(wú)需了解集合的內(nèi)部結(jié)構(gòu)。
-
統(tǒng)一遍歷接口:迭代器模式定義了一個(gè)統(tǒng)一的遍歷接口,包括獲取下一個(gè)元素、判斷是否還有元素、重置迭代器等方法。所有的迭代器都實(shí)現(xiàn)了這個(gè)接口,使得客戶端可以通過(guò)相同的方式來(lái)遍歷不同類(lèi)型的集合。
-
支持多種遍歷方式:迭代器模式可以支持多種不同的遍歷方式,例如順序遍歷、逆序遍歷、深度優(yōu)先遍歷、廣度優(yōu)先遍歷等。通過(guò)提供不同的迭代器實(shí)現(xiàn)類(lèi),客戶端可以選擇合適的遍歷方式來(lái)滿足自己的需求。
總之,迭代器模式的核心思想是通過(guò)將遍歷邏輯抽象出來(lái),使得集合和遍歷邏輯可以獨(dú)立變化,從而提高了代碼的靈活性和可維護(hù)性。
適用場(chǎng)景
迭代器模式適用于以下場(chǎng)景:
-
需要訪問(wèn)一個(gè)聚合對(duì)象的內(nèi)容,而又不暴露其內(nèi)部表示的情況:迭代器模式可以提供一種訪問(wèn)聚合對(duì)象的方式,同時(shí)又不暴露其內(nèi)部結(jié)構(gòu)和實(shí)現(xiàn)細(xì)節(jié),從而使得客戶端可以安全地遍歷集合中的元素。
-
需要對(duì)聚合對(duì)象提供多種遍歷方式:迭代器模式可以定義多個(gè)不同的迭代器實(shí)現(xiàn)類(lèi),每個(gè)實(shí)現(xiàn)類(lèi)可以提供不同的遍歷方式,如順序遍歷、逆序遍歷、深度優(yōu)先遍歷、廣度優(yōu)先遍歷等,從而滿足不同的需求。
-
需要統(tǒng)一對(duì)待不同類(lèi)型的聚合對(duì)象:通過(guò)使用迭代器模式,可以為不同類(lèi)型的聚合對(duì)象提供統(tǒng)一的遍歷接口,使得客戶端可以以相同的方式處理不同類(lèi)型的集合,提高了代碼的復(fù)用性和可擴(kuò)展性。
-
需要在不同集合之間切換遍歷方式:迭代器模式可以為集合對(duì)象提供多個(gè)不同的迭代器實(shí)現(xiàn)類(lèi),客戶端可以根據(jù)需要在不同的集合之間切換遍歷方式,而無(wú)需修改客戶端代碼,從而提高了代碼的靈活性。
總之,迭代器模式適用于需要統(tǒng)一訪問(wèn)集合對(duì)象并提供多種遍歷方式的情況,以及需要解耦集合對(duì)象和遍歷邏輯的情況。
優(yōu)缺點(diǎn)
迭代器模式的優(yōu)點(diǎn)包括:
-
簡(jiǎn)化集合遍歷:迭代器模式提供了一種統(tǒng)一的方式來(lái)遍歷集合對(duì)象,無(wú)需關(guān)心集合的具體實(shí)現(xiàn)細(xì)節(jié),使得遍歷操作變得簡(jiǎn)單和統(tǒng)一。
-
解耦集合和遍歷邏輯:通過(guò)迭代器模式,集合對(duì)象和遍歷邏輯之間的耦合度降低,集合對(duì)象可以獨(dú)立于遍歷算法進(jìn)行變化和修改,從而提高了代碼的靈活性和可維護(hù)性。
-
多種遍歷方式:迭代器模式可以定義多個(gè)不同的迭代器實(shí)現(xiàn)類(lèi),每個(gè)實(shí)現(xiàn)類(lèi)可以提供不同的遍歷方式,使得客戶端可以根據(jù)需要選擇合適的遍歷方式,從而滿足不同的需求。
-
支持逆向遍歷:迭代器模式可以支持逆向遍歷,即從集合末尾向集合開(kāi)頭遍歷,這在某些情況下是非常有用的。
迭代器模式的缺點(diǎn)包括:
-
增加了系統(tǒng)復(fù)雜度:引入迭代器模式會(huì)增加額外的類(lèi)和接口,增加了系統(tǒng)的復(fù)雜度,特別是在需要定義多種不同的迭代器實(shí)現(xiàn)類(lèi)時(shí),可能會(huì)導(dǎo)致類(lèi)的數(shù)量增加。
-
遍歷速度慢:在某些情況下,使用迭代器模式可能會(huì)導(dǎo)致遍歷速度較慢,特別是在遍歷大型集合對(duì)象時(shí),因?yàn)槊看蔚夹枰{(diào)用迭代器的方法。
-
不適合對(duì)數(shù)據(jù)結(jié)構(gòu)修改頻繁的情況:迭代器模式適用于對(duì)集合對(duì)象進(jìn)行頻繁遍歷的情況,但不適用于對(duì)集合對(duì)象進(jìn)行頻繁修改的情況,因?yàn)樵诒闅v過(guò)程中修改集合對(duì)象可能會(huì)導(dǎo)致迭代器失效或遍歷結(jié)果不確定。
組合模式【Composite Pattern】?
定義
組合模式(Composite Pattern)是一種結(jié)構(gòu)型設(shè)計(jì)模式,有時(shí)又叫做部分—整體模式(Part-Whole),主要是用來(lái)描述整體與部分的關(guān)系,用的最多的地方就是樹(shù)形結(jié)構(gòu)。它允許我們將對(duì)象組合成樹(shù)形結(jié)構(gòu)來(lái)表現(xiàn)“整體—部分”的層次結(jié)構(gòu)。組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
組合模式允許客戶端代碼統(tǒng)一對(duì)待單個(gè)對(duì)象和組合對(duì)象。在組合模式中,單個(gè)對(duì)象(葉節(jié)點(diǎn))和組合對(duì)象(樹(shù)枝節(jié)點(diǎn))都實(shí)現(xiàn)了相同的接口,這樣客戶端就可以統(tǒng)一調(diào)用這些對(duì)象的方法,而無(wú)需關(guān)心它們是單個(gè)對(duì)象還是組合對(duì)象。組合模式通過(guò)遞歸組合的方式來(lái)構(gòu)建樹(shù)形結(jié)構(gòu),使得整個(gè)結(jié)構(gòu)可以被一致地處理。
在組合模式中,一般會(huì)有以下角色:
-
Component(組件): 定義組合中所有對(duì)象的通用接口,可以是抽象類(lèi)或接口,聲明了葉子節(jié)點(diǎn)和組合節(jié)點(diǎn)的共同點(diǎn),提供了管理子節(jié)點(diǎn)的方法,如添加、移除、獲取子節(jié)點(diǎn)等。
-
Leaf(葉子節(jié)點(diǎn)): 表示組合中的葉子節(jié)點(diǎn)對(duì)象,它沒(méi)有子節(jié)點(diǎn),實(shí)現(xiàn)了組件接口的方法。
-
Composite(組合節(jié)點(diǎn)): 表示組合中的組合節(jié)點(diǎn)對(duì)象,它有子節(jié)點(diǎn),通常存儲(chǔ)子節(jié)點(diǎn)的集合,并實(shí)現(xiàn)了組件接口的方法,用于管理其子節(jié)點(diǎn)。
在組合模式中,可以根據(jù)葉子節(jié)點(diǎn)和組合節(jié)點(diǎn)的公共接口是否包含對(duì)子節(jié)點(diǎn)的管理方法來(lái)區(qū)分兩種不同的實(shí)現(xiàn)方式,即透明模式和安全模式。
-
透明模式(Transparent Mode):
- 在透明模式中,抽象組件(Component)接口中包含了對(duì)子節(jié)點(diǎn)的管理方法,如添加子節(jié)點(diǎn)、移除子節(jié)點(diǎn)、獲取子節(jié)點(diǎn)等。這意味著無(wú)論是葉子節(jié)點(diǎn)還是組合節(jié)點(diǎn)都必須實(shí)現(xiàn)這些管理方法,即使葉子節(jié)點(diǎn)并不具備子節(jié)點(diǎn),但它們?nèi)匀恍枰峁┻@些方法。
- 透明模式讓客戶端對(duì)葉子節(jié)點(diǎn)和組合節(jié)點(diǎn)的處理更加統(tǒng)一,因?yàn)樗鼈兌甲裱讼嗤慕涌?。但是,葉子節(jié)點(diǎn)實(shí)現(xiàn)了一些對(duì)于自身并不適用的方法,這可能會(huì)導(dǎo)致一些不必要的復(fù)雜性。
-
安全模式(Safe Mode):
- 在安全模式中,抽象組件(Component)接口不包含對(duì)子節(jié)點(diǎn)的管理方法,而是將這些方法放在了組合節(jié)點(diǎn)(Composite)中。葉子節(jié)點(diǎn)(Leaf)不需要實(shí)現(xiàn)這些管理方法,因?yàn)樗鼈儽旧砭蜎](méi)有子節(jié)點(diǎn)。
- 安全模式更加清晰和簡(jiǎn)潔,每個(gè)對(duì)象都只需要實(shí)現(xiàn)自己相關(guān)的方法,不會(huì)有額外的冗余。但是,客戶端需要對(duì)葉子節(jié)點(diǎn)和組合節(jié)點(diǎn)進(jìn)行類(lèi)型檢查,以確保調(diào)用的方法是合法的,這可能增加一些額外的邏輯處理。
因此,透明模式在提供統(tǒng)一接口方面更加便利,但可能會(huì)引入一些不必要的方法實(shí)現(xiàn);而安全模式更加清晰簡(jiǎn)潔,但需要客戶端對(duì)節(jié)點(diǎn)類(lèi)型進(jìn)行檢查以確保方法調(diào)用的合法性。選擇適合的模式取決于具體的應(yīng)用場(chǎng)景和需求。
舉例說(shuō)明
假設(shè)你是一位園藝愛(ài)好者,你有一個(gè)植物園,里面有各種各樣的植物,包括樹(shù)木、花卉和灌木等?,F(xiàn)在你想要設(shè)計(jì)一個(gè)植物目錄系統(tǒng),方便游客查找和了解各種植物。
在這個(gè)場(chǎng)景中,你可以使用組合模式來(lái)管理植物目錄。你可以將植物分為兩種類(lèi)型:?jiǎn)蝹€(gè)植物和植物組合。單個(gè)植物指的是具體的一種植物,例如玫瑰、松樹(shù)等;而植物組合則是由多種植物組成的集合,例如花園、森林等。
當(dāng)你開(kāi)始設(shè)計(jì)植物目錄系統(tǒng)時(shí),首先需要考慮的是如何表示植物及其組合。為此,你可以創(chuàng)建一個(gè)抽象的植物組件接口,讓所有植物和植物組合都實(shí)現(xiàn)這個(gè)接口。這樣,無(wú)論是單個(gè)植物還是植物組合,都能夠被當(dāng)做同一種類(lèi)型來(lái)處理。
// 植物組件接口
interface PlantComponent {
void display();
}
接著,你可以定義兩個(gè)具體的類(lèi)來(lái)實(shí)現(xiàn)這個(gè)接口:?jiǎn)蝹€(gè)植物類(lèi)和植物組合類(lèi)。單個(gè)植物類(lèi)表示具體的一種植物,它會(huì)包含植物的名稱(chēng)、描述等信息;而植物組合類(lèi)表示由多種植物組成的集合,它會(huì)包含一個(gè)植物列表,用來(lái)存儲(chǔ)所有組成該組合的植物。
// 單個(gè)植物類(lèi)
class SinglePlant implements PlantComponent {
private String name;
private String description;
public SinglePlant(String name, String description) {
this.name = name;
this.description = description;
}
@Override
public void display() {
System.out.println("植物名稱(chēng):" + name);
System.out.println("植物描述:" + description);
}
}
在創(chuàng)建植物目錄時(shí),你可以按照層次結(jié)構(gòu)逐步組合植物。比如,你可以先創(chuàng)建一些單個(gè)植物對(duì)象,如玫瑰、松樹(shù)等,然后將它們組合成一個(gè)花園,再將多個(gè)花園組合成一個(gè)更大的景點(diǎn),如森林或者公園。
import java.util.ArrayList;
import java.util.List;
// 植物組合類(lèi)
class PlantComposite implements PlantComponent {
private List<PlantComponent> children = new ArrayList<>();
// 添加植物或植物組合
public void add(PlantComponent component) {
children.add(component);
}
// 移除植物或植物組合
public void remove(PlantComponent component) {
children.remove(component);
}
@Override
public void display() {
for (PlantComponent component : children) {
component.display();
}
}
}
除了表示植物的層次結(jié)構(gòu)外,你還可以為植物組合類(lèi)提供一些額外的方法,如添加植物、移除植物等,以便動(dòng)態(tài)地管理植物的組成。
最后,在展示植物目錄時(shí),你可以調(diào)用植物組合類(lèi)的顯示方法,它會(huì)遞歸地遍歷所有的子植物和子植物組合,并將它們的信息逐一展示出來(lái),讓游客能夠清晰地了解每種植物及其組合的情況。
public class Main {
public static void main(String[] args) {
// 創(chuàng)建單個(gè)植物
SinglePlant rose = new SinglePlant("玫瑰", "紅色花朵");
SinglePlant pine = new SinglePlant("松樹(shù)", "常綠樹(shù)木");
// 創(chuàng)建植物組合
PlantComposite garden = new PlantComposite();
garden.add(rose);
garden.add(pine);
// 創(chuàng)建更大的植物組合
PlantComposite forest = new PlantComposite();
forest.add(garden);
// 顯示植物目錄
System.out.println("植物目錄:");
forest.display();
}
}
這樣一來(lái),你就可以利用組合模式來(lái)設(shè)計(jì)一個(gè)靈活而強(qiáng)大的植物目錄系統(tǒng),方便游客查找和了解各種植物,同時(shí)也為你管理植物園提供了便利。
核心思想
組合模式的核心思想是將對(duì)象組織成樹(shù)形結(jié)構(gòu),使得單個(gè)對(duì)象和組合對(duì)象(容器對(duì)象)具有一致的接口,從而使客戶端可以統(tǒng)一地對(duì)待單個(gè)對(duì)象和組合對(duì)象。這種統(tǒng)一性使得客戶端無(wú)需關(guān)心處理的是單個(gè)對(duì)象還是組合對(duì)象,而只需通過(guò)統(tǒng)一的接口進(jìn)行操作。
具體來(lái)說(shuō),組合模式由以下幾個(gè)要點(diǎn)構(gòu)成其核心思想:
-
抽象構(gòu)件(Component): 定義了對(duì)象接口,可以是組合對(duì)象或葉子對(duì)象,它們具有相同的接口,可以作為組合結(jié)構(gòu)的基類(lèi)。抽象構(gòu)件聲明了在組合對(duì)象和葉子對(duì)象中都可以被調(diào)用的操作。
-
葉子構(gòu)件(Leaf): 是組合結(jié)構(gòu)中的葉子節(jié)點(diǎn),表示對(duì)象的基本單元,葉子節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn),通常實(shí)現(xiàn)了抽象構(gòu)件接口的操作。
-
組合構(gòu)件(Composite): 是組合結(jié)構(gòu)中的容器節(jié)點(diǎn),可以包含葉子節(jié)點(diǎn)和其他組合節(jié)點(diǎn),它實(shí)現(xiàn)了抽象構(gòu)件接口,并且通常包含了一個(gè)集合用于存儲(chǔ)子節(jié)點(diǎn)。
-
客戶端(Client): 通過(guò)抽象構(gòu)件接口操作組合結(jié)構(gòu),客戶端無(wú)需區(qū)分是單個(gè)對(duì)象還是組合對(duì)象,統(tǒng)一地處理組合結(jié)構(gòu)中的各個(gè)節(jié)點(diǎn)。
-
遞歸遍歷: 組合模式通常使用遞歸來(lái)遍歷組合結(jié)構(gòu),客戶端可以通過(guò)遞歸遍歷整個(gè)樹(shù)形結(jié)構(gòu),從而對(duì)組合對(duì)象和葉子對(duì)象進(jìn)行操作。
總的來(lái)說(shuō),組合模式的核心思想是通過(guò)統(tǒng)一的接口和樹(shù)形結(jié)構(gòu)來(lái)組織對(duì)象,使得客戶端可以統(tǒng)一地對(duì)待單個(gè)對(duì)象和組合對(duì)象,從而簡(jiǎn)化了客戶端的使用和維護(hù)
適用場(chǎng)景
組合模式適用于以下場(chǎng)景:
-
對(duì)象的結(jié)構(gòu)具有樹(shù)形層次結(jié)構(gòu): 當(dāng)對(duì)象的結(jié)構(gòu)呈現(xiàn)樹(shù)形層次結(jié)構(gòu),且客戶端需要統(tǒng)一地處理單個(gè)對(duì)象和組合對(duì)象時(shí),可以考慮使用組合模式。例如,文件系統(tǒng)中的文件夾和文件之間的關(guān)系,以及菜單和菜單項(xiàng)之間的關(guān)系。
-
希望客戶端統(tǒng)一處理單個(gè)對(duì)象和組合對(duì)象: 當(dāng)希望客戶端能夠統(tǒng)一地對(duì)待單個(gè)對(duì)象和組合對(duì)象時(shí),組合模式可以很好地滿足這一需求??蛻舳藷o(wú)需關(guān)心處理的是單個(gè)對(duì)象還是組合對(duì)象,只需通過(guò)統(tǒng)一的接口進(jìn)行操作。
-
需要遞歸地處理組合對(duì)象的情況: 組合模式適用于需要遞歸地處理組合對(duì)象的情況。通過(guò)遞歸遍歷整個(gè)樹(shù)形結(jié)構(gòu),可以方便地對(duì)組合對(duì)象和葉子對(duì)象進(jìn)行操作。
-
希望在不同層次對(duì)對(duì)象進(jìn)行操作: 組合模式可以讓客戶端在不同的層次對(duì)對(duì)象進(jìn)行操作,例如在樹(shù)形結(jié)構(gòu)中,客戶端可以在整個(gè)樹(shù)上進(jìn)行操作,也可以?xún)H在某個(gè)分支上進(jìn)行操作,從而實(shí)現(xiàn)靈活的操作。
組合模式適用于對(duì)象的結(jié)構(gòu)具有樹(shù)形層次結(jié)構(gòu),且希望客戶端能夠統(tǒng)一處理單個(gè)對(duì)象和組合對(duì)象的情況。
優(yōu)缺點(diǎn)
組合模式(Composite Pattern)的優(yōu)點(diǎn)和缺點(diǎn)如下:
優(yōu)點(diǎn):
- 統(tǒng)一的接口: 組合模式提供了統(tǒng)一的接口,使得客戶端可以統(tǒng)一處理單個(gè)對(duì)象和組合對(duì)象,簡(jiǎn)化了客戶端的代碼邏輯。
- 靈活性: 可以通過(guò)組合模式輕松地構(gòu)建樹(shù)形結(jié)構(gòu),且可以動(dòng)態(tài)地添加或刪除對(duì)象,從而實(shí)現(xiàn)靈活的結(jié)構(gòu)。
- 易于擴(kuò)展: 添加新類(lèi)型的組合對(duì)象或葉子對(duì)象很容易,不會(huì)影響到已有的代碼。
- 便于管理: 組合模式將單個(gè)對(duì)象和組合對(duì)象統(tǒng)一對(duì)待,使得對(duì)象的管理更加方便。
缺點(diǎn):
- 設(shè)計(jì)復(fù)雜性: 實(shí)現(xiàn)組合模式可能需要定義多個(gè)類(lèi)和接口,增加了系統(tǒng)的復(fù)雜性。
- 不易理解: 對(duì)于初學(xué)者來(lái)說(shuō),理解組合模式的思想可能有一定難度,需要花費(fèi)一些時(shí)間和精力。
- 性能問(wèn)題: 在處理大量對(duì)象時(shí),可能會(huì)帶來(lái)一些性能上的開(kāi)銷(xiāo),因?yàn)樾枰f歸遍歷整個(gè)樹(shù)形結(jié)構(gòu)。
總的來(lái)說(shuō),組合模式適用于需要構(gòu)建樹(shù)形結(jié)構(gòu)并統(tǒng)一處理單個(gè)對(duì)象和組合對(duì)象的情況,但在設(shè)計(jì)時(shí)需要權(quán)衡好復(fù)雜性和性能問(wèn)題。
觀察者模式【Observer Pattern】
定義
觀察者模式是一種行為設(shè)計(jì)模式,它允許對(duì)象(稱(chēng)為觀察者)訂閱另一個(gè)對(duì)象(稱(chēng)為主題或可觀察者),以便在主題狀態(tài)發(fā)生變化時(shí)自動(dòng)接收通知。在觀察者模式中,主題維護(hù)一組觀察者,并在其狀態(tài)發(fā)生變化時(shí)通知它們,使得觀察者可以自動(dòng)更新。
具體來(lái)說(shuō),觀察者模式包含以下幾個(gè)關(guān)鍵角色:
-
Subject(主題):也稱(chēng)為可觀察者,維護(hù)一組觀察者對(duì)象,并提供方法來(lái)注冊(cè)(訂閱)和移除觀察者,以及通知觀察者狀態(tài)變化的方法。
-
Observer(觀察者):定義一個(gè)更新接口,使得在主題狀態(tài)發(fā)生變化時(shí)能夠得到通知并進(jìn)行相應(yīng)的更新操作。
-
ConcreteSubject(具體主題):實(shí)現(xiàn)主題接口,具體主題內(nèi)部狀態(tài)發(fā)生變化時(shí)會(huì)通知其注冊(cè)的所有觀察者。
-
ConcreteObserver(具體觀察者):實(shí)現(xiàn)觀察者接口,定義具體的更新邏輯,以便在接收到主題通知時(shí)進(jìn)行相應(yīng)的更新操作。
通過(guò)觀察者模式,實(shí)現(xiàn)了主題與觀察者之間的解耦,使得主題狀態(tài)變化時(shí)能夠靈活地通知到所有相關(guān)的觀察者,從而實(shí)現(xiàn)了對(duì)象之間的一對(duì)多依賴(lài)關(guān)系。
舉例說(shuō)明
假設(shè)你經(jīng)營(yíng)一家寵物商店,你想要實(shí)現(xiàn)一個(gè)寵物領(lǐng)養(yǎng)系統(tǒng),讓用戶可以及時(shí)了解到新到達(dá)的可愛(ài)小動(dòng)物。在這個(gè)場(chǎng)景中,你可以使用觀察者模式來(lái)實(shí)現(xiàn)。
具體地說(shuō),你可以將用戶視為觀察者(或訂閱者),而新到達(dá)的小動(dòng)物視為目標(biāo)(或主題)。當(dāng)有新的小動(dòng)物到達(dá)時(shí),所有訂閱了通知的用戶都會(huì)收到相應(yīng)的消息,以便他們可以及時(shí)了解到并前來(lái)領(lǐng)養(yǎng)。
這個(gè)例子中,寵物商店管理員充當(dāng)主題,而顧客充當(dāng)觀察者。當(dāng)有新的小動(dòng)物到達(dá)時(shí),管理員會(huì)通知所有已訂閱的顧客,并提供相關(guān)的信息,如動(dòng)物種類(lèi)、性別、年齡等。顧客可以根據(jù)這些信息來(lái)決定是否前來(lái)領(lǐng)養(yǎng)新的小寵物。
import java.util.ArrayList;
import java.util.List;
// 主題接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String animalType, String gender, int age);
}
// 具體主題:寵物商店管理員
class PetStoreManager implements Subject {
private List<Observer> observers;
public PetStoreManager() {
this.observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String animalType, String gender, int age) {
for (Observer observer : observers) {
observer.update(animalType, gender, age);
}
}
// 新到達(dá)小動(dòng)物的方法
public void newAnimalArrival(String animalType, String gender, int age) {
System.out.println("New animal arrived: " + animalType + ", " + gender + ", " + age + " years old");
notifyObservers(animalType, gender, age);
}
}
// 觀察者接口
interface Observer {
void update(String animalType, String gender, int age);
}
// 具體觀察者:顧客
class Customer implements Observer {
private String name;
public Customer(String name) {
this.name = name;
}
@Override
public void update(String animalType, String gender, int age) {
System.out.println(name + " received notification: New " + animalType + " available - Gender: " + gender + ", Age: " + age);
}
}
public class PetAdoptionSystem {
public static void main(String[] args) {
// 創(chuàng)建寵物商店管理員
PetStoreManager petStoreManager = new PetStoreManager();
// 創(chuàng)建兩個(gè)顧客
Customer customer1 = new Customer("Alice");
Customer customer2 = new Customer("Bob");
// 注冊(cè)顧客為觀察者
petStoreManager.registerObserver(customer1);
petStoreManager.registerObserver(customer2);
// 模擬新小動(dòng)物到達(dá)
petStoreManager.newAnimalArrival("Cat", "Male", 2);
petStoreManager.newAnimalArrival("Dog", "Female", 1);
// 顧客可以選擇領(lǐng)養(yǎng)
// ...
}
}
核心思想
觀察者模式的核心思想是定義了一種一對(duì)多的依賴(lài)關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象。當(dāng)這個(gè)主題對(duì)象的狀態(tài)發(fā)生變化時(shí),所有依賴(lài)于它的觀察者都會(huì)得到通知并自動(dòng)更新。
這種設(shè)計(jì)模式的核心思想可以總結(jié)為兩點(diǎn):
-
解耦性:觀察者模式實(shí)現(xiàn)了主題和觀察者之間的解耦。主題不需要知道觀察者的具體實(shí)現(xiàn),只需知道它們都實(shí)現(xiàn)了相同的接口即可。這樣一來(lái),主題對(duì)象可以自由地改變和添加觀察者,而不需要修改自身的代碼。
-
通知機(jī)制:主題對(duì)象維護(hù)了一個(gè)觀察者列表,當(dāng)自身狀態(tài)發(fā)生變化時(shí),會(huì)依次通知所有的觀察者。這種通知機(jī)制使得觀察者可以實(shí)時(shí)獲取到主題的最新?tīng)顟B(tài),并進(jìn)行相應(yīng)的處理和更新。
總的來(lái)說(shuō),觀察者模式的核心思想是基于事件的通知機(jī)制,它允許對(duì)象之間建立一種松耦合的關(guān)系,從而實(shí)現(xiàn)了對(duì)象之間的動(dòng)態(tài)交互和通信。
適用場(chǎng)景
觀察者模式通常在以下情況下使用:
-
當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化需要通知其他對(duì)象,并且不需要知道具體是哪些對(duì)象需要被通知時(shí),可以使用觀察者模式。這樣的情況下,被觀察對(duì)象(主題)就充當(dāng)了消息的發(fā)布者,而觀察者則充當(dāng)了消息的訂閱者。
-
當(dāng)一個(gè)對(duì)象需要將自己的變化通知給多個(gè)其他對(duì)象,并且這些對(duì)象需要在狀態(tài)變化后執(zhí)行不同的操作時(shí),也可以使用觀察者模式。觀察者模式允許多個(gè)觀察者訂閱同一個(gè)主題,每個(gè)觀察者可以根據(jù)自身需要執(zhí)行相應(yīng)的操作,而不需要被通知的對(duì)象知道其他對(duì)象的存在。
觀察者模式適用于以下場(chǎng)景:
-
發(fā)布-訂閱系統(tǒng):當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化需要通知其他對(duì)象,并且這些對(duì)象的數(shù)量和類(lèi)型在運(yùn)行時(shí)可能發(fā)生變化時(shí),可以使用觀察者模式。例如,新聞?dòng)嗛喯到y(tǒng)中,訂閱者可以選擇訂閱感興趣的新聞主題,并在發(fā)布新聞時(shí)收到相應(yīng)的通知。
發(fā)布/訂閱模型就是觀察者模式的一種變體,也被稱(chēng)為 Pub/Sub 模式。與傳統(tǒng)的觀察者模式不同,發(fā)布/訂閱模型中,發(fā)布者(發(fā)布主題)和訂閱者之間不直接進(jìn)行通信,而是通過(guò)一個(gè)稱(chēng)為消息代理(Message Broker)或事件通道(Event Channel)的中介來(lái)進(jìn)行交互。
在發(fā)布/訂閱模型中,發(fā)布者(或稱(chēng)為生產(chǎn)者)負(fù)責(zé)向消息代理發(fā)布消息,而訂閱者(或稱(chēng)為消費(fèi)者)則向消息代理訂閱感興趣的主題或頻道。當(dāng)發(fā)布者發(fā)布了新的消息時(shí),消息代理會(huì)將消息傳遞給所有訂閱了相應(yīng)主題的訂閱者。
這種模式的好處是發(fā)布者和訂閱者之間解耦,發(fā)布者不需要知道誰(shuí)訂閱了它的消息,而訂閱者也不需要知道消息來(lái)自哪個(gè)發(fā)布者。這樣可以更靈活地組織和管理消息傳遞,適用于分布式系統(tǒng)和大規(guī)模應(yīng)用場(chǎng)景。
-
GUI開(kāi)發(fā):在圖形用戶界面(GUI)開(kāi)發(fā)中,經(jīng)常需要實(shí)時(shí)更新界面上的數(shù)據(jù)或狀態(tài),觀察者模式可以用于實(shí)現(xiàn)界面和數(shù)據(jù)之間的同步。例如,一個(gè)數(shù)據(jù)模型的變化可以觸發(fā)多個(gè)界面組件的更新。
-
事件驅(qū)動(dòng)系統(tǒng):在事件驅(qū)動(dòng)的系統(tǒng)中,觀察者模式常被用于處理事件的訂閱和分發(fā)。當(dāng)某個(gè)事件發(fā)生時(shí),可以通知所有相關(guān)的觀察者進(jìn)行相應(yīng)的處理。例如,網(wǎng)絡(luò)服務(wù)器收到請(qǐng)求時(shí),可以通過(guò)觀察者模式通知注冊(cè)的請(qǐng)求處理器進(jìn)行處理。
-
異步編程:在異步編程中,觀察者模式可以用于處理異步任務(wù)的完成通知。當(dāng)一個(gè)異步任務(wù)完成時(shí),可以通知所有注冊(cè)的觀察者進(jìn)行后續(xù)的處理。例如,JavaScript中的Promise對(duì)象就提供了類(lèi)似的觀察者機(jī)制。
關(guān)于觀察者模式的兩個(gè)重點(diǎn)問(wèn)題:
-
廣播鏈的問(wèn)題:當(dāng)觀察者模式中的觀察者之間存在相互依賴(lài)或者相互通知的情況時(shí),可能會(huì)形成廣播鏈,導(dǎo)致不必要的性能消耗和邏輯復(fù)雜度。為了解決這個(gè)問(wèn)題,可以使用消息代理或者事件總線等中間件來(lái)進(jìn)行消息的發(fā)布和訂閱,將消息的傳遞和處理解耦,避免形成廣播鏈。
-
異步處理問(wèn)題:當(dāng)觀察者模式中的消息處理邏輯比較復(fù)雜或者耗時(shí)較長(zhǎng)時(shí),可能會(huì)阻塞消息的發(fā)布者,影響系統(tǒng)的響應(yīng)速度。為了解決這個(gè)問(wèn)題,可以使用異步處理機(jī)制來(lái)處理觀察者收到的消息,將消息的處理邏輯放在異步任務(wù)中進(jìn)行處理,從而提高系統(tǒng)的并發(fā)能力和響應(yīng)速度。當(dāng)然,異步處理就要考慮線程安全和隊(duì)列的問(wèn)題。
總的來(lái)說(shuō),觀察者模式適用于任何需要在對(duì)象之間建立動(dòng)態(tài)的、松耦合的通信機(jī)制的場(chǎng)景。它可以幫助實(shí)現(xiàn)對(duì)象之間的解耦,提高系統(tǒng)的靈活性和可維護(hù)性。
優(yōu)缺點(diǎn)
觀察者模式的優(yōu)點(diǎn)包括:
-
松耦合性:觀察者模式使得目標(biāo)對(duì)象和觀察者對(duì)象之間保持松耦合關(guān)系,它們之間并不直接相互調(diào)用,而是通過(guò)抽象的接口進(jìn)行通信。
-
可擴(kuò)展性:通過(guò)增加或移除觀察者,可以靈活地?cái)U(kuò)展系統(tǒng)的功能,無(wú)需修改目標(biāo)對(duì)象或其他觀察者。
-
復(fù)用性:觀察者模式使得目標(biāo)對(duì)象和觀察者對(duì)象可以在不同的地方復(fù)用,增加了代碼的可復(fù)用性。
-
通知機(jī)制:目標(biāo)對(duì)象發(fā)生變化時(shí),會(huì)自動(dòng)通知所有注冊(cè)的觀察者,使得觀察者可以及時(shí)獲取更新的信息。
觀察者模式的缺點(diǎn)包括:
-
過(guò)多的細(xì)節(jié):當(dāng)觀察者很多時(shí),目標(biāo)對(duì)象通知所有觀察者可能會(huì)導(dǎo)致性能問(wèn)題。此外,如果觀察者之間有循環(huán)依賴(lài)關(guān)系,可能會(huì)導(dǎo)致系統(tǒng)的復(fù)雜性增加。
-
可能引起內(nèi)存泄漏:在Java等語(yǔ)言中,如果觀察者沒(méi)有被正確地釋放,可能會(huì)導(dǎo)致內(nèi)存泄漏問(wèn)題。
-
通知順序不確定:觀察者模式中觀察者的通知順序通常是不確定的,這可能會(huì)導(dǎo)致一些問(wèn)題,例如某個(gè)觀察者依賴(lài)于其他觀察者的通知順序。
綜上所述,觀察者模式適用于需要實(shí)現(xiàn)對(duì)象之間松耦合、動(dòng)態(tài)通信的場(chǎng)景,但在設(shè)計(jì)時(shí)需要注意控制觀察者數(shù)量,避免過(guò)多的細(xì)節(jié)和潛在的性能問(wèn)題。
責(zé)任鏈模式【Chain of Responsibility Pattern】
定義
責(zé)任鏈模式(Chain of Responsibility Pattern)是一種行為設(shè)計(jì)模式,用于解耦發(fā)送者和接收者之間的請(qǐng)求。在該模式中,多個(gè)對(duì)象(處理者)依次處理同一個(gè)請(qǐng)求,直到其中一個(gè)處理者能夠處理該請(qǐng)求為止。
責(zé)任鏈模式包含一系列對(duì)象,每個(gè)對(duì)象都有指定的職責(zé)。當(dāng)收到請(qǐng)求時(shí),每個(gè)對(duì)象有兩種處理方式:
- 將請(qǐng)求傳遞給下一個(gè)處理者。
- 自己處理請(qǐng)求。
責(zé)任鏈模式的核心思想是將多個(gè)處理者組成一條鏈,請(qǐng)求沿著這條鏈傳遞,直到有一個(gè)處理者能夠處理它為止。這樣可以使請(qǐng)求的發(fā)送者和接收者解耦,同時(shí)靈活地添加、修改或移除處理者,而不會(huì)影響到整個(gè)鏈條的結(jié)構(gòu)。
在責(zé)任鏈模式中,通常會(huì)建立一個(gè)抽象處理者(Handler)類(lèi),其中包含處理請(qǐng)求的方法以及一個(gè)指向下一個(gè)處理者的引用。具體的處理者(ConcreteHandler)繼承自抽象處理者,并實(shí)現(xiàn)自己的處理邏輯和判斷條件。當(dāng)收到請(qǐng)求時(shí),抽象處理者首先判斷自己是否能夠處理該請(qǐng)求,如果可以則進(jìn)行處理,否則將請(qǐng)求傳遞給下一個(gè)處理者,直到有一個(gè)處理者能夠處理它為止。
舉例說(shuō)明
假設(shè)你是一家快遞公司的客服代表,負(fù)責(zé)處理客戶的投訴問(wèn)題。有時(shí)候客戶可能會(huì)投訴包裹未按時(shí)送達(dá)、包裹損壞或丟失等問(wèn)題。為了高效處理這些投訴,你可以使用責(zé)任鏈模式。
在這個(gè)場(chǎng)景中,快遞公司的客戶投訴可以分為多個(gè)級(jí)別,例如普通投訴、緊急投訴和重大投訴。每個(gè)級(jí)別的投訴都需要不同級(jí)別的處理者來(lái)處理,而且處理者之間存在著優(yōu)先級(jí)關(guān)系。
具體地說(shuō),你作為客服代表是責(zé)任鏈的起始點(diǎn),負(fù)責(zé)接收客戶的投訴并進(jìn)行初步處理。如果投訴是普通級(jí)別的,你可以直接處理;如果是緊急級(jí)別的,你需要將投訴轉(zhuǎn)發(fā)給緊急處理者;如果是重大級(jí)別的,你需要將投訴轉(zhuǎn)發(fā)給重大處理者。
緊急處理者可能是客戶服務(wù)主管,負(fù)責(zé)處理一些比較緊急但不是很?chē)?yán)重的投訴問(wèn)題,例如包裹送錯(cuò)地址、派送延誤等。而重大處理者可能是公司高層管理人員,負(fù)責(zé)處理一些非常嚴(yán)重的投訴問(wèn)題,例如大面積包裹丟失、嚴(yán)重的服務(wù)質(zhì)量問(wèn)題等。
這樣,當(dāng)客戶提交投訴時(shí),投訴會(huì)根據(jù)其級(jí)別被依次轉(zhuǎn)發(fā)給不同級(jí)別的處理者,直到找到合適的處理者為止。這就是責(zé)任鏈模式的核心思想:將請(qǐng)求沿著處理鏈進(jìn)行傳遞和處理,直到有一個(gè)處理者能夠處理該請(qǐng)求為止。
// 客戶投訴類(lèi)
class CustomerComplaint {
private String level;
private String description;
public CustomerComplaint(String level, String description) {
this.level = level;
this.description = description;
}
public String getLevel() {
return level;
}
public String getDescription() {
return description;
}
}
// 投訴處理者接口
interface ComplaintHandler {
void handleComplaint(CustomerComplaint complaint);
}
// 客服代表,責(zé)任鏈的起始點(diǎn)
class CustomerServiceRepresentative implements ComplaintHandler {
private ComplaintHandler nextHandler;
public void setNextHandler(ComplaintHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handleComplaint(CustomerComplaint complaint) {
if (complaint.getLevel().equals("普通")) {
System.out.println("客服代表處理了普通投訴:" + complaint.getDescription());
} else if (nextHandler != null) {
nextHandler.handleComplaint(complaint);
} else {
System.out.println("沒(méi)有合適的處理者來(lái)處理投訴:" + complaint.getDescription());
}
}
}
// 緊急處理者
class EmergencyHandler implements ComplaintHandler {
private ComplaintHandler nextHandler;
public void setNextHandler(ComplaintHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handleComplaint(CustomerComplaint complaint) {
if (complaint.getLevel().equals("緊急")) {
System.out.println("緊急處理者處理了緊急投訴:" + complaint.getDescription());
} else if (nextHandler != null) {
nextHandler.handleComplaint(complaint);
} else {
System.out.println("沒(méi)有合適的處理者來(lái)處理投訴:" + complaint.getDescription());
}
}
}
// 重大處理者
class MajorHandler implements ComplaintHandler {
@Override
public void handleComplaint(CustomerComplaint complaint) {
if (complaint.getLevel().equals("重大")) {
System.out.println("重大處理者處理了重大投訴:" + complaint.getDescription());
} else {
System.out.println("沒(méi)有合適的處理者來(lái)處理投訴:" + complaint.getDescription());
}
}
}
// 客戶端代碼
public class ComplaintHandlingSystem {
public static void main(String[] args) {
CustomerServiceRepresentative representative = new CustomerServiceRepresentative();
EmergencyHandler emergencyHandler = new EmergencyHandler();
MajorHandler majorHandler = new MajorHandler();
// 設(shè)置責(zé)任鏈關(guān)系
representative.setNextHandler(emergencyHandler);
emergencyHandler.setNextHandler(majorHandler);
// 模擬客戶投訴
CustomerComplaint complaint1 = new CustomerComplaint("普通", "包裹未按時(shí)送達(dá)");
CustomerComplaint complaint2 = new CustomerComplaint("緊急", "包裹損壞");
CustomerComplaint complaint3 = new CustomerComplaint("重大", "大面積包裹丟失");
// 客服代表處理投訴
representative.handleComplaint(complaint1);
representative.handleComplaint(complaint2);
representative.handleComplaint(complaint3);
}
}
核心思想
責(zé)任鏈模式的核心思想是將請(qǐng)求的發(fā)送者和接收者解耦,通過(guò)一條鏈(鏈表)將多個(gè)接收者組織起來(lái),每個(gè)接收者都有機(jī)會(huì)處理請(qǐng)求。當(dāng)請(qǐng)求被發(fā)送時(shí),它沿著這條鏈傳遞,直到有一個(gè)接收者處理它為止。這樣可以避免請(qǐng)求的發(fā)送者需要知道具體的接收者,從而提高系統(tǒng)的靈活性和可擴(kuò)展性。
具體而言,責(zé)任鏈模式包含一系列處理者(Handler)對(duì)象,每個(gè)處理者都有指定的職責(zé)和處理邏輯。當(dāng)一個(gè)請(qǐng)求到達(dá)時(shí),它首先由鏈中的第一個(gè)處理者進(jìn)行處理。如果該處理者能夠處理該請(qǐng)求,則處理完畢;否則,它將請(qǐng)求傳遞給鏈中的下一個(gè)處理者,以此類(lèi)推,直到有一個(gè)處理者處理了請(qǐng)求為止。
責(zé)任鏈模式的核心思想是將請(qǐng)求和處理者解耦,每個(gè)處理者只需關(guān)心自己能否處理請(qǐng)求,而不需要關(guān)心請(qǐng)求的具體來(lái)源和去向。這樣可以輕松地添加、修改或刪除處理者,而不會(huì)影響到整個(gè)系統(tǒng)的結(jié)構(gòu)和穩(wěn)定性。
適用場(chǎng)景
責(zé)任鏈模式通常適用于以下場(chǎng)景:
-
請(qǐng)求需要被多個(gè)對(duì)象處理:當(dāng)一個(gè)請(qǐng)求需要經(jīng)過(guò)多個(gè)對(duì)象處理,并且每個(gè)對(duì)象都可能處理或部分處理該請(qǐng)求時(shí),可以使用責(zé)任鏈模式。例如,一個(gè)請(qǐng)求需要經(jīng)過(guò)多個(gè)審批層級(jí)才能最終被批準(zhǔn)。
-
請(qǐng)求的處理者之間存在動(dòng)態(tài)變化:責(zé)任鏈模式允許動(dòng)態(tài)地增加或修改處理者,而不需要修改客戶端代碼。這使得系統(tǒng)更加靈活和可擴(kuò)展。例如,在一個(gè)日志處理系統(tǒng)中,可以根據(jù)需要?jiǎng)討B(tài)地添加不同級(jí)別的日志處理者。
-
請(qǐng)求的發(fā)送者不需要知道具體的處理者:責(zé)任鏈模式可以將請(qǐng)求的發(fā)送者和接收者解耦,發(fā)送者只需將請(qǐng)求發(fā)送到責(zé)任鏈上,而不需要知道具體的接收者是誰(shuí)。
-
請(qǐng)求需要被處理者中的一個(gè)或多個(gè)處理:責(zé)任鏈模式可以確保一個(gè)請(qǐng)求被處理者中的一個(gè)或多個(gè)處理,而不是只有一個(gè)處理者處理請(qǐng)求。這種情況下,每個(gè)處理者都有機(jī)會(huì)對(duì)請(qǐng)求進(jìn)行處理,增加了系統(tǒng)的靈活性和可配置性。
優(yōu)缺點(diǎn)
責(zé)任鏈模式的優(yōu)點(diǎn)包括:
-
降低耦合度:責(zé)任鏈模式將請(qǐng)求的發(fā)送者和接收者解耦,發(fā)送者不需要知道具體的接收者是誰(shuí),而只需將請(qǐng)求發(fā)送到責(zé)任鏈上即可。這樣可以降低系統(tǒng)各部分之間的耦合度,提高系統(tǒng)的靈活性和可維護(hù)性。
-
靈活性和可擴(kuò)展性:責(zé)任鏈模式允許動(dòng)態(tài)地增加或修改處理者,而不需要修改客戶端代碼。這樣可以根據(jù)需要靈活地調(diào)整責(zé)任鏈的結(jié)構(gòu)和處理邏輯,使系統(tǒng)更具可擴(kuò)展性。
-
責(zé)任分擔(dān):責(zé)任鏈模式將請(qǐng)求分配給多個(gè)處理者,每個(gè)處理者都有機(jī)會(huì)對(duì)請(qǐng)求進(jìn)行處理。這樣可以避免將所有處理邏輯集中到一個(gè)類(lèi)中,提高代碼的可讀性和可維護(hù)性。
-
單一職責(zé)原則:每個(gè)具體處理者只需關(guān)注自己的處理邏輯,不需要關(guān)心其他處理者的實(shí)現(xiàn)細(xì)節(jié)。這有助于確保每個(gè)類(lèi)都遵循單一職責(zé)原則,使代碼更加清晰和易于理解。
責(zé)任鏈模式的缺點(diǎn)包括:
-
請(qǐng)求處理不確定性:由于請(qǐng)求的處理者是動(dòng)態(tài)確定的,并且一個(gè)請(qǐng)求可能被多個(gè)處理者處理,因此可能導(dǎo)致請(qǐng)求的處理結(jié)果不確定性,難以追蹤和調(diào)試。
-
性能問(wèn)題:責(zé)任鏈模式可能會(huì)導(dǎo)致請(qǐng)求在責(zé)任鏈上遍歷多次,直到找到合適的處理者為止。如果責(zé)任鏈過(guò)長(zhǎng)或處理者邏輯復(fù)雜,可能會(huì)影響系統(tǒng)的性能。
-
可能導(dǎo)致循環(huán)引用:在責(zé)任鏈中,處理者之間可能會(huì)相互引用,形成閉環(huán)。如果處理者之間的引用關(guān)系設(shè)置不當(dāng),可能會(huì)導(dǎo)致循環(huán)引用,從而影響系統(tǒng)的正常運(yùn)行。
補(bǔ)充說(shuō)明:觀察者廣播鏈和責(zé)任鏈雖然都涉及到消息的傳遞,但它們?cè)趯?shí)現(xiàn)方式和應(yīng)用場(chǎng)景上有明顯的區(qū)別:
-
受眾數(shù)量不同:
- 觀察者廣播鏈可以實(shí)現(xiàn) 1:N 的方式廣播,即一個(gè)事件發(fā)生后可以通知多個(gè)觀察者,并且每個(gè)觀察者可以再通知其他觀察者,形成一個(gè)廣播鏈。
- 責(zé)任鏈要求是 1:1 的傳遞,即一個(gè)請(qǐng)求只能被一個(gè)責(zé)任鏈中的處理者處理,責(zé)任鏈中的節(jié)點(diǎn)是線性的,請(qǐng)求只能按照責(zé)任鏈的順序依次傳遞,直到找到合適的處理者為止。
-
請(qǐng)求內(nèi)容不同:
- 觀察者廣播鏈中的信息可以在傳播中改變,每個(gè)觀察者都可以對(duì)接收到的消息進(jìn)行處理或修改,并將修改后的消息傳遞給下一個(gè)觀察者。這種情況下,消息的內(nèi)容可能會(huì)隨著傳播路徑的不同而改變。
- 責(zé)任鏈中的請(qǐng)求是不可改變的,一旦請(qǐng)求被創(chuàng)建,其內(nèi)容就不會(huì)在傳遞過(guò)程中改變。責(zé)任鏈中的每個(gè)處理者要么處理請(qǐng)求,要么將請(qǐng)求傳遞給下一個(gè)處理者,不會(huì)對(duì)請(qǐng)求進(jìn)行修改。
-
處理邏輯不同:
- 觀察者廣播鏈主要用于觸發(fā)聯(lián)動(dòng)動(dòng)作,當(dāng)一個(gè)事件發(fā)生時(shí),通過(guò)觀察者模式通知所有相關(guān)的觀察者,并讓它們執(zhí)行相應(yīng)的動(dòng)作,形成一個(gè)聯(lián)動(dòng)。
- 責(zé)任鏈則是對(duì)一個(gè)類(lèi)型的請(qǐng)求按照既定的規(guī)則進(jìn)行處理,責(zé)任鏈中的每個(gè)節(jié)點(diǎn)都有可能處理請(qǐng)求,但只有符合特定條件的節(jié)點(diǎn)才會(huì)真正處理請(qǐng)求,其他節(jié)點(diǎn)會(huì)將請(qǐng)求傳遞給下一個(gè)節(jié)點(diǎn)。
總的來(lái)說(shuō),觀察者廣播鏈適用于需要多個(gè)對(duì)象之間進(jìn)行松耦合通信的場(chǎng)景,而責(zé)任鏈適用于需要按照特定順序處理請(qǐng)求,并且每個(gè)請(qǐng)求只能被一個(gè)處理者處理的場(chǎng)景。
訪問(wèn)者模式【Visitor Pattern】?
定義
訪問(wèn)者模式(Visitor Pattern)是一種行為設(shè)計(jì)模式,它允許我們?cè)诓恍薷默F(xiàn)有類(lèi)的情況下定義一些新的操作。訪問(wèn)者模式將算法與操作的元素結(jié)構(gòu)進(jìn)行分離,使得可以在不修改這些元素的情況下,定義作用于這些元素的新操作。
具體來(lái)說(shuō),訪問(wèn)者模式包含以下幾個(gè)要素:
-
訪問(wèn)者(Visitor):定義了對(duì)對(duì)象結(jié)構(gòu)中每個(gè)元素進(jìn)行訪問(wèn)的操作。這些操作可以是不同的,根據(jù)具體的需求進(jìn)行設(shè)計(jì)。通常情況下,訪問(wèn)者模式會(huì)定義一個(gè)抽象的訪問(wèn)者接口,包含對(duì)每個(gè)元素對(duì)象進(jìn)行訪問(wèn)的方法。
-
具體訪問(wèn)者(Concrete Visitor):實(shí)現(xiàn)了訪問(wèn)者接口,提供了對(duì)元素對(duì)象的不同操作的具體實(shí)現(xiàn)。每個(gè)具體訪問(wèn)者都可以根據(jù)需要來(lái)定義自己的操作。
-
元素對(duì)象(Element):定義了一個(gè)接受訪問(wèn)者訪問(wèn)的接口,通常包含一個(gè)接受操作的方法。元素對(duì)象可以是單個(gè)對(duì)象,也可以是一個(gè)對(duì)象的集合。
-
具體元素對(duì)象(Concrete Element):實(shí)現(xiàn)了元素對(duì)象接口,提供了具體的接受操作的實(shí)現(xiàn)。
-
對(duì)象結(jié)構(gòu)(Object Structure):扮演了元素對(duì)象的容器角色,可以是一個(gè)單獨(dú)的對(duì)象,也可以是一個(gè)集合。對(duì)象結(jié)構(gòu)提供了一個(gè)接受訪問(wèn)者訪問(wèn)的方法,使得訪問(wèn)者可以訪問(wèn)對(duì)象結(jié)構(gòu)中的每個(gè)元素對(duì)象。
通過(guò)訪問(wèn)者模式,我們可以在不修改元素對(duì)象的情況下,定義新的操作,同時(shí)也不會(huì)破壞元素對(duì)象的封裝性。這種分離了元素對(duì)象和操作的設(shè)計(jì)方式使得訪問(wèn)者模式在處理復(fù)雜的對(duì)象結(jié)構(gòu)和多種操作時(shí)非常有用。
舉例說(shuō)明
假設(shè)你是一位博物館管理員,你管理著一個(gè)博物館,里面展示著各種珍貴的文物,包括陶器、繪畫(huà)、雕塑等。現(xiàn)在你想要設(shè)計(jì)一個(gè)文物評(píng)估系統(tǒng),方便專(zhuān)家對(duì)文物進(jìn)行評(píng)估,并根據(jù)評(píng)估結(jié)果進(jìn)行分類(lèi)和處理。
在這個(gè)場(chǎng)景中,你可以使用訪問(wèn)者模式來(lái)實(shí)現(xiàn)文物評(píng)估系統(tǒng)。你可以將文物分為不同的類(lèi)型,例如陶器、繪畫(huà)、雕塑等,每種類(lèi)型的文物都有自己的特點(diǎn)和評(píng)估標(biāo)準(zhǔn)。評(píng)估專(zhuān)家可以作為訪問(wèn)者,根據(jù)自己的專(zhuān)業(yè)領(lǐng)域?qū)ξ奈镞M(jìn)行評(píng)估,并給出評(píng)估結(jié)果。
具體地說(shuō),你可以設(shè)計(jì)一個(gè)文物類(lèi)(Artifact),其中包含各種類(lèi)型的文物,例如陶器、繪畫(huà)、雕塑等。然后你可以設(shè)計(jì)一個(gè)評(píng)估專(zhuān)家接口(Evaluator),其中包含各種評(píng)估方法,例如評(píng)估陶器的質(zhì)量、繪畫(huà)的藝術(shù)價(jià)值、雕塑的歷史意義等。每個(gè)評(píng)估專(zhuān)家都實(shí)現(xiàn)了評(píng)估接口中的方法,根據(jù)自己的專(zhuān)業(yè)領(lǐng)域?qū)ξ奈镞M(jìn)行評(píng)估。最后,你可以設(shè)計(jì)一個(gè)評(píng)估系統(tǒng)(EvaluationSystem),負(fù)責(zé)管理文物和評(píng)估專(zhuān)家,并將文物交給評(píng)估專(zhuān)家進(jìn)行評(píng)估,然后根據(jù)評(píng)估結(jié)果進(jìn)行分類(lèi)和處理。
這個(gè)例子中,博物館管理員充當(dāng)對(duì)象結(jié)構(gòu),各種類(lèi)型的文物充當(dāng)具體元素,評(píng)估專(zhuān)家充當(dāng)訪問(wèn)者,評(píng)估系統(tǒng)充當(dāng)客戶端。評(píng)估系統(tǒng)將文物交給評(píng)估專(zhuān)家進(jìn)行評(píng)估,然后根據(jù)評(píng)估結(jié)果進(jìn)行后續(xù)處理,實(shí)現(xiàn)了文物評(píng)估系統(tǒng)的設(shè)計(jì)和應(yīng)用。
// 文物接口
interface Artifact {
void accept(Evaluator evaluator);
}
// 具體文物:陶器
class Pottery implements Artifact {
@Override
public void accept(Evaluator evaluator) {
evaluator.evaluatePottery(this);
}
}
// 具體文物:繪畫(huà)
class Painting implements Artifact {
@Override
public void accept(Evaluator evaluator) {
evaluator.evaluatePainting(this);
}
}
// 具體文物:雕塑
class Sculpture implements Artifact {
@Override
public void accept(Evaluator evaluator) {
evaluator.evaluateSculpture(this);
}
}
// 評(píng)估專(zhuān)家接口
interface Evaluator {
void evaluatePottery(Pottery pottery);
void evaluatePainting(Painting painting);
void evaluateSculpture(Sculpture sculpture);
}
// 具體評(píng)估專(zhuān)家:陶器評(píng)估專(zhuān)家
class PotteryEvaluator implements Evaluator {
@Override
public void evaluatePottery(Pottery pottery) {
System.out.println("評(píng)估陶器的質(zhì)量和歷史價(jià)值。");
}
@Override
public void evaluatePainting(Painting painting) {
// 陶器評(píng)估專(zhuān)家不評(píng)估繪畫(huà)
}
@Override
public void evaluateSculpture(Sculpture sculpture) {
// 陶器評(píng)估專(zhuān)家不評(píng)估雕塑
}
}
// 具體評(píng)估專(zhuān)家:繪畫(huà)評(píng)估專(zhuān)家
class PaintingEvaluator implements Evaluator {
@Override
public void evaluatePottery(Pottery pottery) {
// 繪畫(huà)評(píng)估專(zhuān)家不評(píng)估陶器
}
@Override
public void evaluatePainting(Painting painting) {
System.out.println("評(píng)估繪畫(huà)的藝術(shù)價(jià)值和歷史意義。");
}
@Override
public void evaluateSculpture(Sculpture sculpture) {
// 繪畫(huà)評(píng)估專(zhuān)家不評(píng)估雕塑
}
}
// 具體評(píng)估專(zhuān)家:雕塑評(píng)估專(zhuān)家
class SculptureEvaluator implements Evaluator {
@Override
public void evaluatePottery(Pottery pottery) {
// 雕塑評(píng)估專(zhuān)家不評(píng)估陶器
}
@Override
public void evaluatePainting(Painting painting) {
// 雕塑評(píng)估專(zhuān)家不評(píng)估繪畫(huà)
}
@Override
public void evaluateSculpture(Sculpture sculpture) {
System.out.println("評(píng)估雕塑的藝術(shù)價(jià)值和歷史意義。");
}
}
// 評(píng)估系統(tǒng)
class EvaluationSystem {
public static void main(String[] args) {
// 創(chuàng)建文物
Artifact[] artifacts = { new Pottery(), new Painting(), new Sculpture() };
// 創(chuàng)建評(píng)估專(zhuān)家
Evaluator potteryEvaluator = new PotteryEvaluator();
Evaluator paintingEvaluator = new PaintingEvaluator();
Evaluator sculptureEvaluator = new SculptureEvaluator();
// 評(píng)估文物
for (Artifact artifact : artifacts) {
artifact.accept(potteryEvaluator);
artifact.accept(paintingEvaluator);
artifact.accept(sculptureEvaluator);
}
}
}
核心思想
訪問(wèn)者模式的核心思想是將數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作相分離。它通過(guò)在數(shù)據(jù)結(jié)構(gòu)中添加一個(gè)接受訪問(wèn)者訪問(wèn)的方法,并將具體的數(shù)據(jù)操作封裝在訪問(wèn)者中,實(shí)現(xiàn)了對(duì)數(shù)據(jù)結(jié)構(gòu)的操作與數(shù)據(jù)結(jié)構(gòu)本身的解耦。
具體來(lái)說(shuō),訪問(wèn)者模式的核心思想包括以下幾點(diǎn):
-
數(shù)據(jù)結(jié)構(gòu):數(shù)據(jù)結(jié)構(gòu)由一組元素組成,這些元素可以是單個(gè)對(duì)象,也可以是對(duì)象的集合。數(shù)據(jù)結(jié)構(gòu)通常包含一個(gè)接受訪問(wèn)者訪問(wèn)的方法,即accept(visitor)方法,通過(guò)該方法,數(shù)據(jù)結(jié)構(gòu)可以接受不同的訪問(wèn)者來(lái)進(jìn)行操作。
-
訪問(wèn)者:訪問(wèn)者是對(duì)數(shù)據(jù)結(jié)構(gòu)中元素進(jìn)行操作的對(duì)象。訪問(wèn)者包含了一系列具體的操作方法,每個(gè)方法用于處理數(shù)據(jù)結(jié)構(gòu)中的不同類(lèi)型的元素。通過(guò)訪問(wèn)者模式,可以將對(duì)數(shù)據(jù)結(jié)構(gòu)的操作從數(shù)據(jù)結(jié)構(gòu)中分離出來(lái),使得可以根據(jù)需要定義不同的操作,而無(wú)需修改數(shù)據(jù)結(jié)構(gòu)本身。
-
雙分派機(jī)制:在訪問(wèn)者模式中,存在一種雙分派(Double Dispatch)的機(jī)制。在調(diào)用元素對(duì)象的accept(visitor)方法時(shí),實(shí)際執(zhí)行的是訪問(wèn)者中與該元素對(duì)象類(lèi)型匹配的方法。這種雙分派機(jī)制使得可以根據(jù)元素對(duì)象和訪問(wèn)者的實(shí)際類(lèi)型來(lái)確定執(zhí)行的操作,從而實(shí)現(xiàn)了動(dòng)態(tài)綁定。
-
適用于復(fù)雜對(duì)象結(jié)構(gòu):訪問(wèn)者模式適用于處理復(fù)雜的對(duì)象結(jié)構(gòu),例如組合模式中的樹(shù)形結(jié)構(gòu)。通過(guò)訪問(wèn)者模式,可以將對(duì)復(fù)雜對(duì)象結(jié)構(gòu)的操作統(tǒng)一封裝在訪問(wèn)者中,簡(jiǎn)化了代碼的管理和維護(hù)。
總之,訪問(wèn)者模式的核心思想是通過(guò)在數(shù)據(jù)結(jié)構(gòu)中添加接受訪問(wèn)者的方法,并將具體的操作封裝在訪問(wèn)者中,實(shí)現(xiàn)了數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作的解耦,使得可以根據(jù)需要定義不同的操作,而無(wú)需修改數(shù)據(jù)結(jié)構(gòu)本身。
適用場(chǎng)景
訪問(wèn)者模式通常適用于以下場(chǎng)景:
-
對(duì)象結(jié)構(gòu)穩(wěn)定,但操作算法經(jīng)常變化:當(dāng)對(duì)象結(jié)構(gòu)相對(duì)穩(wěn)定,但需要對(duì)其進(jìn)行多種不同的操作時(shí),可以考慮使用訪問(wèn)者模式。通過(guò)將操作封裝在不同的訪問(wèn)者中,可以輕松地添加新的操作,而無(wú)需修改對(duì)象結(jié)構(gòu)。
-
對(duì)象結(jié)構(gòu)包含多種不同類(lèi)型的元素:當(dāng)對(duì)象結(jié)構(gòu)中包含多種不同類(lèi)型的元素,并且針對(duì)每種元素需要執(zhí)行不同的操作時(shí),訪問(wèn)者模式是一種有效的設(shè)計(jì)方式。通過(guò)在訪問(wèn)者中定義針對(duì)不同類(lèi)型元素的操作方法,可以靈活地處理對(duì)象結(jié)構(gòu)中的各種元素。
-
數(shù)據(jù)結(jié)構(gòu)與操作分離:訪問(wèn)者模式適用于需要將數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作相分離的場(chǎng)景。通過(guò)將操作封裝在訪問(wèn)者中,可以使得數(shù)據(jù)結(jié)構(gòu)專(zhuān)注于自身的組織結(jié)構(gòu),而操作則由訪問(wèn)者來(lái)負(fù)責(zé)執(zhí)行,實(shí)現(xiàn)了數(shù)據(jù)結(jié)構(gòu)與操作的解耦。
-
對(duì)對(duì)象結(jié)構(gòu)的操作需要擴(kuò)展,而不希望修改對(duì)象結(jié)構(gòu)本身:當(dāng)需要對(duì)對(duì)象結(jié)構(gòu)的操作進(jìn)行擴(kuò)展,但不希望修改對(duì)象結(jié)構(gòu)本身時(shí),可以考慮使用訪問(wèn)者模式。通過(guò)添加新的訪問(wèn)者來(lái)擴(kuò)展操作,可以實(shí)現(xiàn)對(duì)對(duì)象結(jié)構(gòu)的功能增強(qiáng),同時(shí)保持對(duì)象結(jié)構(gòu)的穩(wěn)定性。
訪問(wèn)者模式適用于需要對(duì)對(duì)象結(jié)構(gòu)中的多種元素進(jìn)行不同操作,并且希望將操作與對(duì)象結(jié)構(gòu)解耦的場(chǎng)景。它提供了一種靈活的方式來(lái)處理復(fù)雜的對(duì)象結(jié)構(gòu),并支持對(duì)操作的擴(kuò)展和修改,而不影響對(duì)象結(jié)構(gòu)本身。
優(yōu)缺點(diǎn)
訪問(wèn)者模式(Visitor Pattern)具有如下優(yōu)點(diǎn)和缺點(diǎn):
優(yōu)點(diǎn):
- 增加新的操作:訪問(wèn)者模式可以通過(guò)增加新的訪問(wèn)者類(lèi)來(lái)實(shí)現(xiàn)對(duì)已有的對(duì)象結(jié)構(gòu)進(jìn)行新的操作,而無(wú)需修改對(duì)象結(jié)構(gòu)本身,符合開(kāi)閉原則。
- 提高擴(kuò)展性:訪問(wèn)者模式將數(shù)據(jù)結(jié)構(gòu)與操作分離,使得可以在不修改已有代碼的情況下,擴(kuò)展對(duì)象結(jié)構(gòu)的操作。
- 訪問(wèn)者和數(shù)據(jù)結(jié)構(gòu)分離:訪問(wèn)者模式將具體操作封裝在訪問(wèn)者中,使得數(shù)據(jù)結(jié)構(gòu)和操作分離,符合單一職責(zé)原則和開(kāi)閉原則。
- 適用于穩(wěn)定的數(shù)據(jù)結(jié)構(gòu):訪問(wèn)者模式適用于對(duì)象結(jié)構(gòu)相對(duì)穩(wěn)定,但需要經(jīng)常變化的操作算法的場(chǎng)景。
- 符合單一職責(zé)原則:訪問(wèn)者模式將具體元素類(lèi)與訪問(wèn)者類(lèi)分離,每個(gè)類(lèi)負(fù)責(zé)自己的職責(zé),使得系統(tǒng)更加清晰和易于維護(hù)。
- 支持不同的操作集:通過(guò)增加新的訪問(wèn)者類(lèi),可以實(shí)現(xiàn)不同的操作,而不需要修改原有的元素類(lèi),符合開(kāi)閉原則。
- 增加新的數(shù)據(jù)結(jié)構(gòu)較為容易:如果需要在系統(tǒng)中增加新的數(shù)據(jù)結(jié)構(gòu),只需增加新的具體元素類(lèi)和對(duì)應(yīng)的訪問(wèn)者類(lèi)即可,無(wú)需修改原有代碼。
缺點(diǎn):
- 增加新的具體元素類(lèi)和訪問(wèn)者類(lèi)比較困難:如果需要在對(duì)象結(jié)構(gòu)中添加新的元素,需要修改所有訪問(wèn)者類(lèi)的接口,可能會(huì)導(dǎo)致修改量較大。當(dāng)系統(tǒng)中具體元素類(lèi)和訪問(wèn)者類(lèi)較多,且相互之間的關(guān)系比較復(fù)雜時(shí),增加新的類(lèi)可能會(huì)導(dǎo)致類(lèi)的數(shù)量急劇增加,維護(hù)困難。
- 破壞封裝性:訪問(wèn)者模式會(huì)將具體元素暴露給訪問(wèn)者,可能會(huì)破壞對(duì)象的封裝性。
- 增加了系統(tǒng)復(fù)雜度:訪問(wèn)者模式引入了訪問(wèn)者接口、具體訪問(wèn)者、對(duì)象結(jié)構(gòu)等新的角色和類(lèi),可能會(huì)增加系統(tǒng)的復(fù)雜度和理解難度。
- 公開(kāi)了元素的內(nèi)部細(xì)節(jié):為了讓訪問(wèn)者能夠訪問(wèn)元素的內(nèi)部狀態(tài),元素類(lèi)可能需要暴露一些內(nèi)部細(xì)節(jié),這與迪米特法則不太一致,增加了系統(tǒng)的耦合性。
總的來(lái)說(shuō),訪問(wèn)者模式適用于需要對(duì)對(duì)象結(jié)構(gòu)中的元素進(jìn)行多種不同操作,并且希望將操作與對(duì)象結(jié)構(gòu)解耦的場(chǎng)景。它能夠提高系統(tǒng)的擴(kuò)展性和靈活性,但也會(huì)增加系統(tǒng)的復(fù)雜度和理解難度。因此,我們?cè)谑褂迷L問(wèn)者模式時(shí)需要權(quán)衡其優(yōu)缺點(diǎn),根據(jù)具體情況進(jìn)行選擇。
補(bǔ)充說(shuō)明:
訪問(wèn)者模式與迭代器模式有一些相似之處,但它們的關(guān)注點(diǎn)和應(yīng)用場(chǎng)景略有不同。
-
迭代器模式主要關(guān)注遍歷和訪問(wèn)集合中的元素,它提供一種統(tǒng)一的方法來(lái)訪問(wèn)同類(lèi)或同接口的數(shù)據(jù)集合,并隱藏了數(shù)據(jù)集合的具體實(shí)現(xiàn)細(xì)節(jié)。迭代器模式適用于需要順序訪問(wèn)集合元素的情況,例如遍歷列表、數(shù)組等。
-
而訪問(wèn)者模式則更加關(guān)注對(duì)不同類(lèi)型的對(duì)象執(zhí)行不同的操作,它允許在不修改對(duì)象結(jié)構(gòu)的前提下定義新的操作。通過(guò)訪問(wèn)者模式,我們可以將數(shù)據(jù)結(jié)構(gòu)與對(duì)數(shù)據(jù)的操作分離,實(shí)現(xiàn)了數(shù)據(jù)結(jié)構(gòu)和操作的解耦。這使得我們可以輕松地添加新的操作,而無(wú)需修改現(xiàn)有的對(duì)象結(jié)構(gòu)。訪問(wèn)者模式適用于需要對(duì)復(fù)雜對(duì)象結(jié)構(gòu)進(jìn)行操作并且這些操作可能隨時(shí)發(fā)生變化的情況,例如編譯器的語(yǔ)法分析、解釋器的語(yǔ)義分析等。
迭代器模式用于遍歷集合元素,而訪問(wèn)者模式用于對(duì)不同類(lèi)型的對(duì)象執(zhí)行不同的操作,可以作為攔截器(Interceptor)來(lái)攔截對(duì)對(duì)象的訪問(wèn)并執(zhí)行相應(yīng)的操作。
訪問(wèn)者模式是會(huì)經(jīng)常用到的模式,三個(gè)擴(kuò)展功能可供參考:
-
統(tǒng)計(jì)功能:通過(guò)訪問(wèn)者模式,可以輕松實(shí)現(xiàn)對(duì)數(shù)據(jù)的統(tǒng)計(jì)功能。訪問(wèn)者類(lèi)可以針對(duì)不同的元素類(lèi)實(shí)現(xiàn)不同的統(tǒng)計(jì)邏輯,例如計(jì)算總數(shù)、求平均值、查找最大值等,而具體元素類(lèi)則負(fù)責(zé)提供數(shù)據(jù)。這樣,系統(tǒng)就可以實(shí)現(xiàn)靈活的統(tǒng)計(jì)功能,而不需要修改原有的數(shù)據(jù)結(jié)構(gòu)和統(tǒng)計(jì)邏輯。
-
多個(gè)訪問(wèn)者:訪問(wèn)者模式支持多個(gè)訪問(wèn)者對(duì)同一個(gè)對(duì)象結(jié)構(gòu)進(jìn)行訪問(wèn),每個(gè)訪問(wèn)者可以實(shí)現(xiàn)不同的操作,從而實(shí)現(xiàn)對(duì)對(duì)象結(jié)構(gòu)的多種處理。這種靈活性使得系統(tǒng)更加可擴(kuò)展,可以根據(jù)需要隨時(shí)增加新的訪問(wèn)者,而不會(huì)影響已有的訪問(wèn)邏輯。
-
攔截器:通過(guò)訪問(wèn)者模式實(shí)現(xiàn)簡(jiǎn)單的攔截器功能,可以對(duì)被攔截的對(duì)象進(jìn)行檢查和修改。攔截器類(lèi)作為訪問(wèn)者類(lèi),負(fù)責(zé)訪問(wèn)被攔截對(duì)象,并根據(jù)需要進(jìn)行檢查和修改。這樣,系統(tǒng)就可以實(shí)現(xiàn)靈活的攔截器功能,對(duì)數(shù)據(jù)進(jìn)行有效的過(guò)濾和處理,而不需要修改原有的業(yè)務(wù)邏輯。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-854187.html
綜上所述,訪問(wèn)者模式不僅可以實(shí)現(xiàn)基本的數(shù)據(jù)遍歷和操作,還可以通過(guò)擴(kuò)展實(shí)現(xiàn)更加豐富和復(fù)雜的功能,是一種非常靈活和強(qiáng)大的設(shè)計(jì)模式。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-854187.html
到了這里,關(guān)于二十四種設(shè)計(jì)模式與六大設(shè)計(jì)原則(三):【裝飾模式、迭代器模式、組合模式、觀察者模式、責(zé)任鏈模式、訪問(wèn)者模式】的定義、舉例說(shuō)明、核心思想、適用場(chǎng)景和優(yōu)缺點(diǎn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!