創(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 單例
- 只有
private
構(gòu)造方法,確保外部無法實例化; - 通過
private static
變量持有唯一實例,保證全局唯一性; - 通過
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
- 最頂層的Component是接口,對應(yīng)到IO的就是InputStream這個抽象類。
- ComponentA、ComponentB是實際的子類,對應(yīng)到IO的就是FileInputStream、ServletInputStream這些數(shù)據(jù)源。
- Decorator是用于實現(xiàn)各個附加功能的抽象裝飾器,對應(yīng)到IO的就是FilterInputStream。
- 從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
訪問者抽象了訪問者的行為。文章來源地址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)!