国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

設(shè)計模式學(xué)習(xí)筆記

這篇具有很好參考價值的文章主要介紹了設(shè)計模式學(xué)習(xí)筆記。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

創(chuàng)建型

把對象的創(chuàng)建和使用相分離

1 工廠方法

定義工廠接口和產(chǎn)品接口,但如何創(chuàng)建實際工廠和實際產(chǎn)品被推遲到子類實現(xiàn),從而使調(diào)用方只和抽象工廠與抽象產(chǎn)品打交道

調(diào)用方盡量持有接口或抽象類,避免持有具體類型的子類,以便工廠方法能隨時切換不同的子類返回,卻不影響調(diào)用方代碼。

好處:屏蔽創(chuàng)建產(chǎn)品的細(xì)節(jié),可能創(chuàng)建新產(chǎn)品,也可能返回緩存

// 抽象工廠 - 接口,返回抽象產(chǎn)品Number
public interface NumberFactory {
    // 創(chuàng)建方法:
    Number parse(String s);

    // 獲取工廠實例:
    static NumberFactory getFactory() {
        return impl;
    }

    static NumberFactory impl = new NumberFactoryImpl();
}

// 工廠 - (接口)實現(xiàn)類,返回實際產(chǎn)品
public class NumberFactoryImpl implements NumberFactory {
    public Number parse(String s) {
        return new BigDecimal(s);
    }
}

// 客戶端用接口獲得抽象產(chǎn)品
NumberFactory factory = NumberFactory.getFactory();
Number result = factory.parse("123.456");

靜態(tài)工廠方法:使用靜態(tài)方法創(chuàng)建產(chǎn)品

public final class Integer {
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    ...
}
Integer n = Integer.valueOf(100);

List<String> list = List.of("A", "B", "C");

2 抽象工廠

抽象工廠會對應(yīng)到多個實際工廠,每個實際工廠負(fù)責(zé)創(chuàng)建多個實際產(chǎn)品

// 抽象工廠 接口
// 實際工廠 實現(xiàn)類
// 抽象商品 接口
// 實際商品 實現(xiàn)類
// 客戶端創(chuàng)建抽象工廠【類型是實際工廠】,用抽象工廠獲得抽象產(chǎn)品
AbstractFactory factory = new FastFactory();
// 生成Html文檔:
HtmlDocument html = factory.createHtml("#Hello\nHello, world!");
html.save(Paths.get(".", "fast.html"));
// 生成Word文檔:
WordDocument word = factory.createWord("#Hello\nHello, world!");
word.save(Paths.get(".", "fast.doc"));

// 如果把創(chuàng)建工廠的代碼放到AbstractFactory中,就可以連實際工廠也屏蔽了:
public interface AbstractFactory {
    public static AbstractFactory createFactory(String name) {
        if (name.equalsIgnoreCase("fast")) {
            return new FastFactory();
        } else if (name.equalsIgnoreCase("good")) {
            return new GoodFactory();
        } else {
            throw new IllegalArgumentException("Invalid factory name");
        }
    }
}

3 生成器/建造者

Builder.build()

使用多個“小型”工廠來最終創(chuàng)建出一個完整對象。多個步驟組裝成完整對象。

簡化Builder模式,以鏈?zhǔn)秸{(diào)用的方式來創(chuàng)建對象

4 原型

原型模式,即Prototype,是指創(chuàng)建新對象的時候,根據(jù)現(xiàn)有的一個原型來創(chuàng)建。(封裝創(chuàng)建過程)

存儲簡單類型的“值”對象可以復(fù)制

// 類中添加一個clone或者copy方法
	public Object clone() {
        Student std = new Student();
        std.id = this.id;
        std.name = this.name;
        std.score = this.score;
        return std;
	}
    public Student copy() {
        Student std = new Student();
        std.id = this.id;
        std.name = this.name;
        std.score = this.score;
        return std;
    }

5 單例

  1. 只有private構(gòu)造方法,確保外部無法實例化;
  2. 通過private static變量持有唯一實例,保證全局唯一性;
  3. 通過public static方法返回此唯一實例,使外部調(diào)用方能獲取到實例。

提供一個靜態(tài)方法,直接返回實例;或者直接把static變量暴露給外部

public class Singleton {
    // 靜態(tài)字段引用唯一實例:
    private static final Singleton INSTANCE = new Singleton();

    // 通過靜態(tài)方法返回實例:
    public static Singleton getInstance() {
        return INSTANCE;
    }

    // private構(gòu)造方法保證外部無法實例化:
    private Singleton() {
    }
}

多線程時不用延遲加載寫法。

另一種實現(xiàn)Singleton的方式是利用Java的enum,因為Java保證枚舉類的每個枚舉都是單例,所以我們只需要編寫一個只有一個枚舉的類即可。

使用枚舉實現(xiàn)Singleton還避免了第一種方式實現(xiàn)Singleton的一個潛在問題:即序列化和反序列化會繞過普通類的private構(gòu)造方法從而創(chuàng)建出多個實例,而枚舉類就沒有這個問題。

很多程序,尤其是Web程序,大部分服務(wù)類都應(yīng)該被視作Singleton,如果全部按Singleton的寫法寫,會非常麻煩,所以,通常是通過約定讓框架(例如Spring)來實例化這些類,保證只有一個實例,調(diào)用方自覺通過框架獲取實例而不是new操作符。

@Component // 表示一個單例組件

因此,除非確有必要,否則Singleton模式一般以“約定”為主,不會刻意實現(xiàn)它。

結(jié)構(gòu)型

組合各種對象。組合與運行期的動態(tài)組合。

1 適配器

Adapter模式可以將一個A接口轉(zhuǎn)換為B接口,使得新的對象符合B接口規(guī)范。

public BAdapter implements B {
    private A a;
    public BAdapter(A a) {
        this.a = a;
    }
    public void b() {
        a.a();
    }
}

在Adapter內(nèi)部將B接口的調(diào)用“轉(zhuǎn)換”為對A接口的調(diào)用。

2 橋接

橋接模式實現(xiàn)比較復(fù)雜,實際應(yīng)用也非常少,但它提供的設(shè)計思想值得借鑒,即不要過度使用繼承,而是優(yōu)先拆分某些部件,使用組合的方式來擴展功能。

// 抽象類,內(nèi)部組件是引用一個接口
public abstract class Car {
    // 引用Engine:
    protected Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public abstract void drive();
}

// 引擎接口,每一種引擎實現(xiàn)接口
public interface Engine {
    void start();
}

// 修正的抽象類,可以定義額外操作
public abstract class RefinedCar extends Car {
    public RefinedCar(Engine engine) {
        super(engine);
    }

    public void drive() {
        this.engine.start();
        System.out.println("Drive " + getBrand() + " car...");
    }

    public abstract String getBrand();
}

// 實現(xiàn)類繼承 修正的抽象類
public class BossCar extends RefinedCar {
    public BossCar(Engine engine) {
        super(engine);
    }

    public String getBrand() {
        return "Boss";
    }
}

// 客戶端通過自己選擇一個品牌,再配合一種引擎,得到最終的Car
RefinedCar car = new BossCar(new HybridEngine());
car.drive();
       ┌───────────┐
       │    Car    │
       └───────────┘
             ▲
             │
       ┌───────────┐       ┌─────────┐
       │RefinedCar │ ─ ─ ─>│ Engine  │
       └───────────┘       └─────────┘
             ▲                  ▲
    ┌────────┼────────┐         │ ┌──────────────┐
    │        │        │         ├─│  FuelEngine  │
┌───────┐┌───────┐┌───────┐     │ └──────────────┘
│BigCar ││TinyCar││BossCar│     │ ┌──────────────┐
└───────┘└───────┘└───────┘     ├─│ElectricEngine│
                                │ └──────────────┘
                                │ ┌──────────────┐
                                └─│ HybridEngine │
                                  └──────────────┘

3 組合

結(jié)構(gòu)。葉子節(jié)點統(tǒng)一到一個接口。

             ┌───────────┐
             │   Node    │
             └───────────┘
                   ▲
      ┌────────────┼────────────┐
      │            │            │
┌───────────┐┌───────────┐┌───────────┐
│ElementNode││ TextNode  ││CommentNode│
└───────────┘└───────────┘└───────────┘

使用node 操作

Node root = new ElementNode("school");
root.add(new ElementNode("classA")
        .add(new TextNode("Tom"))
        .add(new TextNode("Alice")));
root.add(new ElementNode("classB")
        .add(new TextNode("Bob"))
        .add(new TextNode("Grace"))
        .add(new CommentNode("comment...")));
System.out.println(root.toXml());

4 裝飾器

把核心功能和附加功能給分開了。在運行期動態(tài)給某個對象的實例增加功能的方法。

IO

  1. 最頂層的Component是接口,對應(yīng)到IO的就是InputStream這個抽象類。
  2. ComponentA、ComponentB是實際的子類,對應(yīng)到IO的就是FileInputStream、ServletInputStream這些數(shù)據(jù)源。
  3. Decorator是用于實現(xiàn)各個附加功能的抽象裝飾器,對應(yīng)到IO的就是FilterInputStream。
  4. 從Decorator派生的就是一個一個的裝飾器,它們每個都有獨立的功能,對應(yīng)到IO的就是BufferedInputStream、GZIPInputStream等。
             ┌───────────┐
             │ Component │
             └───────────┘
                   ▲
      ┌────────────┼─────────────────┐
      │            │                 │
┌───────────┐┌───────────┐     ┌───────────┐
│ComponentA ││ComponentB │...  │ Decorator │
└───────────┘└───────────┘     └───────────┘
                                     ▲
                              ┌──────┴──────┐
                              │             │
                        ┌───────────┐ ┌───────────┐
                        │DecoratorA │ │DecoratorB │...
                        └───────────┘ └───────────┘

與橋接的區(qū)別:

裝飾器增加的是功能,功能不是單一的,可以同時存在。所以功能可以一層一層的附加。橋接增加的是某個組件的屬性,多種可選一個,是確定的。

裝飾器和橋接的目的都是降低繼承中衍生的子類的數(shù)量,

橋接是通過把一個組件及其子類作為另一總體的字段引用實現(xiàn)功能組合,也可以用多個組件來拼合總體

裝飾器則在大類下創(chuàng)建一個裝飾器的子族,不管是主要部件還是裝飾器都隸屬于這個大類,所以裝飾器可以不斷嵌套

看起來橋接和裝飾器的使用都是層層調(diào)用,但是兩者的功能不同,橋接的子類是負(fù)責(zé)總體的局部功能,是構(gòu)成性的

而裝飾器則是對已經(jīng)具有了完整功能的總體進(jìn)行修飾,是附加性的。

相當(dāng)于雪中送炭和錦上添花的區(qū)別。

5 外觀

中介??蛻舳酥缓椭薪榇蚪坏馈?/p>

創(chuàng)建一個中介類。中介類去走所有的流程。

6 享元

一經(jīng)創(chuàng)建就不可變的對象實例,直接向調(diào)用方返回一個共享的實例就行

包裝類型如Byte、Integer都是不變類

享元模式就是通過工廠方法創(chuàng)建對象,在工廠方法內(nèi)部,很可能返回緩存的實例,而不是新創(chuàng)建實例,從而實現(xiàn)不可變實例的復(fù)用。

在實際應(yīng)用中,享元模式主要應(yīng)用于緩存,即客戶端如果重復(fù)請求某些對象,不必每次查詢數(shù)據(jù)庫或者讀取文件,而是直接返回內(nèi)存中緩存的數(shù)據(jù)。

7 代理

代理模式通過封裝一個已有接口,并向調(diào)用方返回相同的接口類型,能讓調(diào)用方在不改變?nèi)魏未a的前提下增強某些功能(例如,鑒權(quán)、延遲加載、連接池復(fù)用等)。

使用Proxy模式要求調(diào)用方持有接口,作為Proxy的類也必須實現(xiàn)相同的接口類型。

和外觀中介的區(qū)別

和適配器的區(qū)別:還是把A接口轉(zhuǎn)成A接口,加入額外代碼以實現(xiàn)權(quán)限檢查

用Proxy實現(xiàn)這個權(quán)限檢查,我們可以獲得更清晰、更簡潔的代碼:

  • A接口:只定義接口;
  • ABusiness類:只實現(xiàn)A接口的業(yè)務(wù)邏輯;
  • APermissionProxy類:只實現(xiàn)A接口的權(quán)限檢查代理。

jbdc這塊看不懂……

行為型

描述一組對象應(yīng)該如何協(xié)作來完成一個整體任務(wù)

1 責(zé)任鏈

責(zé)任鏈模式是一種把多個處理器組合在一起,依次處理請求的模式;

責(zé)任鏈模式的好處是添加新的處理器或者重新排列處理器非常容易;

責(zé)任鏈模式經(jīng)常用在攔截、預(yù)處理請求等。

順序重要

// 請求對象 類

// 處理器 接口
public interface Handler {
    // 返回Boolean.TRUE = 成功
    // 返回Boolean.FALSE = 拒絕
    // 返回null = 交下一個處理
	Boolean process(Request request);
}
// 多個處理器 實現(xiàn)類

// 責(zé)任鏈 類,組合Handler
public class HandlerChain {
    // 持有所有Handler:
    private List<Handler> handlers = new ArrayList<>();

    public void addHandler(Handler handler) {
        this.handlers.add(handler);
    }

    public boolean process(Request request) {
        // 依次調(diào)用每個Handler:
        for (Handler handler : handlers) {
            Boolean r = handler.process(request);
            if (r != null) {
                // 如果返回TRUE或FALSE,處理結(jié)束:
                System.out.println(request + " " + (r ? "Approved by " : "Denied by ") + handler.getClass().getSimpleName());
                return r;
            }
        }
        throw new RuntimeException("Could not handle request: " + request);
    }
}

// 構(gòu)造責(zé)任鏈:
HandlerChain chain = new HandlerChain();
chain.addHandler(new ManagerHandler());
chain.addHandler(new DirectorHandler());
chain.addHandler(new CEOHandler());
// 處理請求:
chain.process(new Request("Bob", new BigDecimal("123.45")));
chain.process(new Request("Alice", new BigDecimal("1234.56")));
chain.process(new Request("Bill", new BigDecimal("12345.67")));
chain.process(new Request("John", new BigDecimal("123456.78")));

有些責(zé)任鏈的實現(xiàn)方式是通過某個Handler手動調(diào)用下一個Handler來傳遞Request

還有一些責(zé)任鏈模式,每個Handler都有機會處理Request,通常這種責(zé)任鏈被稱為攔截器(Interceptor)或者過濾器(Filter),它的目的不是找到某個Handler處理掉Request,而是每個Handler都做一些工作

2 命令

請求封裝為對象??蛻舳瞬恍枰私饩庉嬈鞯乃薪涌谛畔ⅰ?/p>

// 命令 接口
public interface Command {
    void execute();
}
// 派生命令 實現(xiàn)類
public class CopyCommand implements Command {
    // 持有執(zhí)行者對象:
    private TextEditor receiver;

    public CopyCommand(TextEditor receiver) {
        this.receiver = receiver;
    }

    public void execute() {
        receiver.copy();
    }
}

// 客戶端
TextEditor editor = new TextEditor();
editor.add("Command pattern in text editor.\n");
// 執(zhí)行一個CopyCommand:
Command copy = new CopyCommand(editor);
copy.execute();
editor.add("----\n");
┌─────────────┐
│   Client    │
└─────────────┘
       │

       │
       ▼
┌─────────────┐
│   Invoker   │
├─────────────┤    ┌───────┐
│List commands│─ ─>│Command│
│invoke(c)    │    └───────┘
│undo()       │        │  ┌──────────────┐
└─────────────┘        ├─>│ CopyCommand  │
                       │  ├──────────────┤
                       │  │editor.copy() │─ ┐
                       │  └──────────────┘
                       │                    │  ┌────────────┐
                       │  ┌──────────────┐   ─>│ TextEditor │
                       └─>│ PasteCommand │  │  └────────────┘
                          ├──────────────┤
                          │editor.paste()│─ ┘
                          └──────────────┘

3 解釋器

解釋器模式通過抽象語法樹實現(xiàn)對用戶輸入的解釋執(zhí)行。

解釋器模式的實現(xiàn)通常非常復(fù)雜,且一般只能解決一類特定問題。

匹配

4 迭代器

順序訪問一個聚合對象中的各個元素,而又不需要暴露該對象的內(nèi)部表示。

如何實現(xiàn)一個Iterator模式

實現(xiàn)Iterator模式的關(guān)鍵是返回一個Iterator對象,該對象知道集合的內(nèi)部結(jié)構(gòu)

public class ReverseArrayCollection<T> implements Iterable<T> {
    private T[] array;

    public ReverseArrayCollection(T... objs) {
        this.array = Arrays.copyOfRange(objs, 0, objs.length);
    }

    public Iterator<T> iterator() {
        return new ReverseIterator();
    }

    class ReverseIterator implements Iterator<T> {
        // 索引位置:
        int index;

        public ReverseIterator() {
            // 創(chuàng)建Iterator時,索引在數(shù)組末尾:
            this.index = ReverseArrayCollection.this.array.length;
        }

        public boolean hasNext() {
            // 如果索引大于0,那么可以移動到下一個元素(倒序往前移動):
            return index > 0;
        }

        public T next() {
            // 將索引移動到下一個元素并返回(倒序往前移動):
            index--;
            return array[index];
        }
    }
}

5 中介

中介模式是通過引入一個中介對象,把多邊關(guān)系變成多個雙邊關(guān)系,從而簡化系統(tǒng)組件的交互耦合度。

與外觀的區(qū)別?

外觀的中介指的是客戶端只和一個外觀類打交道。重在屏蔽處理順序。(給商家付款)

中介模式指的是處理幾個對象之間的多邊關(guān)系。重在減少組件交互耦合。(幾個人之間換錢)

6 備忘錄

在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。

標(biāo)準(zhǔn)的備忘錄模式有這么幾種角色:

  • Memento:存儲的內(nèi)部狀態(tài);
  • Originator:創(chuàng)建一個備忘錄并設(shè)置其狀態(tài);
  • Caretaker:負(fù)責(zé)保存?zhèn)渫洝?/li>

實際上:增加getState()setState()就可以了。

7 觀察者/訂閱發(fā)布模式

// 被觀察者 引用ProductObserver接口
public class Store {
    private List<ProductObserver> observers = new ArrayList<>();
    private Map<String, Product> products = new HashMap<>();

    // 注冊觀察者:
    public void addObserver(ProductObserver observer) {
        this.observers.add(observer);
    }

    // 取消注冊:
    public void removeObserver(ProductObserver observer) {
        this.observers.remove(observer);
    }

    public void addNewProduct(String name, double price) {
        Product p = new Product(name, price);
        products.put(p.getName(), p);
        // 通知觀察者:
        observers.forEach(o -> o.onPublished(p));
    }

    public void setProductPrice(String name, double price) {
        Product p = products.get(name);
        p.setPrice(price);
        // 通知觀察者:
        observers.forEach(o -> o.onPriceChanged(p));
    }
}

// observer:
Admin a = new Admin();
Customer c = new Customer();
// store:
Store store = new Store();
// 注冊觀察者:
store.addObserver(a);
store.addObserver(c);
┌─────────┐      ┌───────────────┐
│  Store  │─ ─ ─>│ProductObserver│
└─────────┘      └───────────────┘
     │                   ▲
                         │
     │             ┌─────┴─────┐
     ▼             │           │
┌─────────┐   ┌─────────┐ ┌─────────┐
│ Product │   │  Admin  │ │Customer │ ...
└─────────┘   └─────────┘ └─────────┘

變體

1 被觀察者也抽象出接口

public interface ProductObservable { // 注意此處拼寫是Observable不是Observer!
    void addObserver(ProductObserver observer);
    void removeObserver(ProductObserver observer);
}

2 通知抽象為Event對象,統(tǒng)一一種通知方法

廣義的觀察者模式包括所有消息系統(tǒng)。所謂消息系統(tǒng),就是把觀察者和被觀察者完全分離,通過消息系統(tǒng)本身來通知

8 狀態(tài)

允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為。對象看起來似乎修改了它的類。

不同狀態(tài)的邏輯分離到不同的狀態(tài)類中,從而使得增加新狀態(tài)更容易。關(guān)鍵在于狀態(tài)轉(zhuǎn)換。

// 狀態(tài) 接口
// 不同狀態(tài) 實現(xiàn)類
// 狀態(tài)切換
public class BotContext {
	private State state = new DisconnectedState();

	public String chat(String input) {
		if ("hello".equalsIgnoreCase(input)) {
            // 收到hello切換到在線狀態(tài):
			state = new ConnectedState();
			return state.init();
		} else if ("bye".equalsIgnoreCase(input)) {
            /  收到bye切換到離線狀態(tài):
			state = new DisconnectedState();
			return state.init();
		}
		return state.reply(input);
	}
}

// 客戶端
Scanner scanner = new Scanner(System.in);
BotContext bot = new BotContext();
for (;;) {
    System.out.print("> ");
    String input = scanner.nextLine();
    String output = bot.chat(input);
    System.out.println(output.isEmpty() ? "(no reply)" : "< " + output);
}

9 策略

允許調(diào)用方選擇一個算法,從而通過不同策略實現(xiàn)不同的計算結(jié)果。

Arrays.sort(array, String::compareToIgnoreCase);

定義策略以及使用策略的上下文

// 策略接口
public interface DiscountStrategy {
    // 計算折扣額度:
    BigDecimal getDiscount(BigDecimal total);
}
// 各種策略 實現(xiàn)類
public class OverDiscountStrategy implements DiscountStrategy {
    public BigDecimal getDiscount(BigDecimal total) {
        // 滿100減20優(yōu)惠:
        return total.compareTo(BigDecimal.valueOf(100)) >= 0 ? BigDecimal.valueOf(20) : BigDecimal.ZERO;
    }
}
// 應(yīng)用策略
public class DiscountContext {
    // 持有某個策略:
    private DiscountStrategy strategy = new UserDiscountStrategy();

    // 允許客戶端設(shè)置新策略:
    public void setStrategy(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public BigDecimal calculatePrice(BigDecimal total) {
        return total.subtract(this.strategy.getDiscount(total)).setScale(2);
    }
}

// 客戶端
DiscountContext ctx = new DiscountContext();

// 默認(rèn)使用普通會員折扣:
BigDecimal pay1 = ctx.calculatePrice(BigDecimal.valueOf(105));
System.out.println(pay1);

// 使用滿減折扣:
ctx.setStrategy(new OverDiscountStrategy());
BigDecimal pay2 = ctx.calculatePrice(BigDecimal.valueOf(105));
System.out.println(pay2);

// 使用Prime會員折扣:
ctx.setStrategy(new PrimeDiscountStrategy());
BigDecimal pay3 = ctx.calculatePrice(BigDecimal.valueOf(105));
System.out.println(pay3);

又會員又滿減,考慮設(shè)計成裝飾器

10 模板方法

定義一個操作的一系列步驟,對于某些暫時確定不下來的步驟,就留給子類去實現(xiàn)好了(用抽象方法),這樣不同的子類就可以定義出不同的步驟。

模板方法的核心在于父類定義骨架,子類實現(xiàn)某些細(xì)節(jié)。

// 骨架,能查找使用緩存
public abstract class AbstractSetting {
    public final String getSetting(String key) {
        String value = lookupCache(key);
        if (value == null) {
            value = readFromDatabase(key);
            putIntoCache(key, value);
        }
        return value;
    }

    protected abstract String lookupCache(String key);

    protected abstract void putIntoCache(String key, String value);
}

// 子類繼承,用什么做緩存都可以
public class LocalSetting extends AbstractSetting {
    private Map<String, String> cache = new HashMap<>();

    protected String lookupCache(String key) {
        return cache.get(key);
    }

    protected void putIntoCache(String key, String value) {
        cache.put(key, value);
    }
}
// 客戶端
AbstractSetting setting1 = new LocalSetting();
System.out.println("test = " + setting1.getSetting("test"));
System.out.println("test = " + setting1.getSetting("test"));

為了防止子類重寫父類的骨架方法,可以在父類中對骨架方法使用final。對于需要子類實現(xiàn)的抽象方法,一般聲明為protected,使得這些方法對外部客戶端不可見。

11 訪問者

一種操作一組對象的操作,它的目的是不改變對象的定義,但允許新增不同的訪問者,來定義新的操作。

為了訪問比較復(fù)雜的數(shù)據(jù)結(jié)構(gòu),不去改變數(shù)據(jù)結(jié)構(gòu),而是把對數(shù)據(jù)的操作抽象出來,在“訪問”的過程中以回調(diào)形式在訪問者中處理操作邏輯。如果要新增一組操作,那么只需要增加一個新的訪問者。

與觀察者區(qū)別:

訪問者抽象了訪問者的行為。文章來源地址http://www.zghlxwxcb.cn/news/detail-826401.html

// 訪問者 接口
public interface Visitor {
    // 訪問文件夾:
    void visitDir(File dir);
    // 訪問文件:
    void visitFile(File file);
}
// 具體的訪問者 實現(xiàn)類

// 持有文件夾和文件的數(shù)據(jù)結(jié)構(gòu)
public class FileStructure {
    // 根目錄:
    private File path;
    public FileStructure(File path) {
        this.path = path;
    }
    
    public void handle(Visitor visitor) {
		scan(this.path, visitor);
	}

	private void scan(File file, Visitor visitor) {
		if (file.isDirectory()) {
            // 讓訪問者處理文件夾:
			visitor.visitDir(file);
			for (File sub : file.listFiles()) {
                // 遞歸處理子文件夾:
				scan(sub, visitor);
			}
		} else if (file.isFile()) {
            // 讓訪問者處理文件:
			visitor.visitFile(file);
		}
	}
}

// 客戶端
FileStructure fs = new FileStructure(new File("."));
fs.handle(new JavaFileVisitor());

到了這里,關(guān)于設(shè)計模式學(xué)習(xí)筆記的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包