怎么創(chuàng)建網(wǎng)站 免費(fèi)的官網(wǎng)設(shè)計公司
文章目錄
- 前言
- 一、命令模式
- 二、訪問者模式
- 三、迭代器模式
前言
??本篇是關(guān)于設(shè)計模式中命令模式、訪問者模式、以及迭代器模式的學(xué)習(xí)筆記。
一、命令模式
??命令模式是一種行為型設(shè)計模式
,其核心目的在于將命令的發(fā)送者和接受者解耦,提供一個中間層對命令進(jìn)行統(tǒng)一的管理,請求的發(fā)送者不需要知道接收者的具體實現(xiàn),而只需依賴一個抽象的命令接口。
??命令模式通常包括以下的角色:
- 抽象/接口命令層:定義了執(zhí)行命令的抽象方法,例如執(zhí)行,撤銷。
- 具體命令類:繼承/實現(xiàn)了命令層,對命令的具體內(nèi)容做一個描述。
- 接收者:實際執(zhí)行操作的對象,包含與請求相關(guān)的邏輯。
- 調(diào)用者:調(diào)用命令對象以觸發(fā)請求的執(zhí)行。
- 客戶端:創(chuàng)建具體的命令對象,并將其綁定到調(diào)用者上。
??舉一個生活中的案例,假設(shè)對于家電,想要通過一個萬能遙控器
去控制某個家電的開/關(guān),而不需要每個家電都配一個遙控器,則可以將開,關(guān)設(shè)為具體命令類:
/*** 命令抽象類*/
public interface Command {/*** 執(zhí)行命令*/void execute();/*** 回滾操作*/void undo();
}
??以對燈的開關(guān)操作為例,開燈的命令類:
/*** 開燈*/
public class LightOnCommand implements Command{private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.on();}@Overridepublic void undo() {light.off();}
}
??關(guān)燈的命令類:
/*** 關(guān)燈*/
public class LightOffCommand implements Command{private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.off();}@Overridepublic void undo() {light.on();}
}
??具體的電器,有開關(guān)的操作。
public class Light {public void on(){System.out.println("把燈打開");}public void off(){System.out.println("關(guān)燈了");}
}
??以及一個空的命令類
:
public class NoCommand implements Command{/*** 執(zhí)行命令*/@Overridepublic void execute() {}/*** 回滾操作*/@Overridepublic void undo() {}
}
??命令的統(tǒng)一管理類,主要作用:
- 對命令組進(jìn)行初始化。
- 設(shè)置操控某一個對象的具體命令。
- 執(zhí)行具體的命令。
- 撤銷命令。
public class RemoteController {//存放各種設(shè)備的開命令Command[] onCommands;//存放各種設(shè)備的關(guān)命令Command[] offCommands;//撤銷的命令Command unCommand;/*** 初始化空命令*/public RemoteController(int number) {onCommands = new Command[number];offCommands = new Command[number];for (int i = 0; i < number; i++) {onCommands[i] = new NoCommand();offCommands[i] = new NoCommand();}}/*** 設(shè)置具體的命令** @param no 設(shè)備組編號* @param onCommand 具體設(shè)備組設(shè)備的開命令* @param offCommand 具體設(shè)備組設(shè)備的關(guān)命令*/public void setCommand(int no, Command onCommand, Command offCommand) {onCommands[no] = onCommand;offCommands[no] = offCommand;}/*** 按下某個設(shè)備的開按鈕** @param no 設(shè)備組編號*/public void onButtonWasPushed(int no) {onCommands[no].execute();//記錄本次操作,便于撤銷unCommand = onCommands[no];}/*** 按下某個設(shè)備的關(guān)按鈕** @param no 設(shè)備組編號*/public void offButtonWasPushed(int no) {offCommands[no].execute();//記錄本次操作,便于撤銷unCommand = offCommands[no];}/*** 撤銷*/public void undo() {unCommand.undo();}
}
??客戶端:
public class Client {public static void main(String[] args) {Light light = new Light();//初始化開啟電燈命令LightOnCommand lightOnCommand = new LightOnCommand(light);//初始化關(guān)閉電燈命令LightOffCommand lightOffCommand = new LightOffCommand(light);//初始化遙控器面板RemoteController remoteController = new RemoteController(5);remoteController.setCommand(0, lightOnCommand, lightOffCommand);System.out.println("--------開啟電燈--------");remoteController.onButtonWasPushed(0);System.out.println("--------關(guān)閉電燈--------");remoteController.offButtonWasPushed(0);System.out.println("--------撤銷上一步操作--------");remoteController.undo();}
}
??如果需要進(jìn)行擴(kuò)展,比如電視,只需要去增加一個電視機(jī)對象
,以及兩個實現(xiàn)了命令接口的具體命令類
,最后在客戶端進(jìn)行初始化即可,無需對命令管理類進(jìn)行修改。
二、訪問者模式
??訪問者模式是一種行為型設(shè)計模式
,主要用來將操作與對象結(jié)構(gòu)分離。核心思想在不修改對象結(jié)構(gòu)的前提下,定義作用于這些對象的新操作。
??訪問者模式通過引入一個訪問者對象,將對結(jié)構(gòu)中各個元素的操作從元素類中抽離出來。這樣,當(dāng)需要添加新操作時,無需修改元素類,而只需添加新的訪問者類,訪問者模式由以下幾個角色組成:
- 訪問者接口:聲明對每種元素類型的訪問操作方法。
- 具體訪問者:實現(xiàn)訪問者接口,定義具體的操作邏輯。
- 元素接口:定義接受訪問者對象的方法。
- 具體元素:實現(xiàn)元素接口,在接受訪問者對象的方法中調(diào)用訪問者的相應(yīng)方法。
- 對象結(jié)構(gòu):包含一組元素,可以遍歷這些元素并讓訪問者訪問它們。
??舉一個生活中的案例,例如在網(wǎng)上商城將商品加入購物車,需要計算商品總價,還需要獲取商品的詳細(xì)清單,利用訪問者模式,可以將商品作為被訪問的類
:
/*** 被訪問的元素接口*/
public interface Item {void accept(Visitor visitor);
}
/*** 被訪問的元素:書籍*/
public class Book implements Item {private String title;private double price;public Book(String title, double price) {this.title = title;this.price = price;}public String getTitle() {return title;}public double getPrice() {return price;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}
/*** 被訪問的元素:電子產(chǎn)品*/
public class Electronic implements Item {private String name;private double price;public Electronic(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public double getPrice() {return price;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}
??定義一個訪問者接口層
,訪問具體的商品(書籍,電子產(chǎn)品):
public interface Visitor {void visit(Book book);void visit(Electronic electronic);
}
??定義計算價格和打印清單具體的行為:
/*** 打印清單*/
public class ItemPrinterVisitor implements Visitor {@Overridepublic void visit(Book book) {System.out.println("Book: " + book.getTitle() + " - Price: " + book.getPrice());}@Overridepublic void visit(Electronic electronic) {System.out.println("Electronic: " + electronic.getName() + " - Price: " + electronic.getPrice());}
}
/*** 計算書籍和電子產(chǎn)品的價格*/
public class PriceCalculatorVisitor implements Visitor{private double totalPrice = 0;@Overridepublic void visit(Book book) {totalPrice = totalPrice+book.getPrice();}@Overridepublic void visit(Electronic electronic) {totalPrice = totalPrice + electronic.getPrice();}public double getTotalPrice(){return totalPrice;}
}
??以及具體的對象接口,讓訪問者去操作書籍和電子產(chǎn)品:
/*** 對象接口*/
public class ShoppingCart {private List<Item> items = new ArrayList<>();public void addItem(Item item) {items.add(item);}public void accept(Visitor visitor) {for (Item item : items) {item.accept(visitor);}}
}
??客戶端:
public class Client {public static void main(String[] args) {// 創(chuàng)建購物車ShoppingCart cart = new ShoppingCart();cart.addItem(new Book("Spring源碼深度解析", 50));cart.addItem(new Electronic("Iphone17", 6300));// 計算總價PriceCalculatorVisitor priceCalculator = new PriceCalculatorVisitor();cart.accept(priceCalculator);System.out.println("Total Price: " + priceCalculator.getTotalPrice());// 打印清單ItemPrinterVisitor itemPrinter = new ItemPrinterVisitor();cart.accept(itemPrinter);}
}
??這樣的好處在于,將具體的操作和對象結(jié)構(gòu)分離,后續(xù)增加具體的操作,無需對對象結(jié)構(gòu)進(jìn)行修改。因此適用于需要對對象結(jié)構(gòu)中的對象執(zhí)行多種不相關(guān)的操作,而操作的實現(xiàn)細(xì)節(jié)需要彼此獨(dú)立的場景。
??同時也可以體會一下如果不使用訪問者模式,會存在怎么樣的弊端:
- 代碼耦合度高:在
ShoppingCart
類中,我們需要判斷每個商品的類型,并為不同類型的商品執(zhí)行不同的操作。這導(dǎo)致了ShoppingCart
類與具體商品類型的緊密耦合。如果要新增一種商品?就又要加一個條件分支。 - 擴(kuò)展性差:同樣地,除了計算價格和打印清單,如果還需要再增加一種操作?那么購物車的代碼還需要進(jìn)行修改。
// 書籍類(Book)
public class Book {private String title;private double price;public Book(String title, double price) {this.title = title;this.price = price;}public String getTitle() {return title;}public double getPrice() {return price;}
}// 電子產(chǎn)品類(ElectronicProduct)
public class ElectronicProduct {private String name;private double price;public ElectronicProduct(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public double getPrice() {return price;}
}
??在購物車中直接計算總價,打印清單:
import java.util.ArrayList;
import java.util.List;public class ShoppingCart {private List<Object> items;public ShoppingCart() {items = new ArrayList<>();}public void addItem(Object item) {items.add(item);}public List<Object> getItems() {return items;}// 計算總價public double calculateTotalPrice() {double totalPrice = 0;for (Object item : items) {if (item instanceof Book) {totalPrice += ((Book) item).getPrice();} else if (item instanceof ElectronicProduct) {totalPrice += ((ElectronicProduct) item).getPrice();}}return totalPrice;}// 打印訂單清單public void printOrderDetails() {System.out.println("Shopping Cart Details:");for (Object item : items) {if (item instanceof Book) {Book book = (Book) item;System.out.println("Book: " + book.getTitle() + ", Price: " + book.getPrice());} else if (item instanceof ElectronicProduct) {ElectronicProduct product = (ElectronicProduct) item;System.out.println("Product: " + product.getName() + ", Price: " + product.getPrice());}}}
}
三、迭代器模式
??迭代器模式是一種行為型設(shè)計模式
,核心思想是將集合的遍歷操作與集合的實現(xiàn)分離,從而不暴露集合的內(nèi)部結(jié)構(gòu),只需要依賴一個公共的接口來訪問集合中的元素。通過這種方式,可以在不改變集合結(jié)構(gòu)的情況下,提供不同的遍歷方式和邏輯,通常包含以下的角色:
- 迭代器接口:定義遍歷集合元素的方法,可以使用JDK的
Iterator
接口。 - 具體迭代器:實現(xiàn)迭代器接口,負(fù)責(zé)具體的遍歷邏輯。
- 聚合接口:定義返回一個迭代器的方法。
- 具體聚合:實現(xiàn)聚合接口,維護(hù)集合的實際數(shù)據(jù)結(jié)構(gòu),并提供創(chuàng)建迭代器的方法。
??假設(shè)現(xiàn)在有一個電商項目,需要管理多個訂單。每個訂單由多個商品組成。希望能夠順序遍歷訂單中的商品,而不暴露訂單內(nèi)部的實現(xiàn)細(xì)節(jié),首先創(chuàng)建一個商品的實例
:
public class Product {private String productName;private double price;public Product(String productName, double price) {this.productName = productName;this.price = price;}public String getProductName() {return productName;}public double getPrice() {return price;}
}
??再編寫一個聚合接口
:
public interface Aggregate {Iterator createIterator();
}
??創(chuàng)建具體聚合
和迭代器接口
public class Order implements Aggregate{private String orderId;private Product[] items;public Order(String orderId, Product[] items) {this.orderId = orderId;this.items = items;}public String getOrderId() {return orderId;}public Product[] getItems() {return items;}@Overridepublic Iterator createIterator() {return new OrderIterator(this);}
}
public class OrderIterator implements Iterator {private Order order;private int index;public OrderIterator(Order order) {this.order = order;this.index = 0;}@Overridepublic boolean hasNext() {return index < order.getItems().length;}@Overridepublic Object next() {if (hasNext()) {return order.getItems()[index++];}return null;}
}
??客戶端,創(chuàng)建產(chǎn)品并且遍歷:
public class Client {public static void main(String[] args) {Product p1 = new Product("產(chǎn)品1", 5);Product p2 = new Product("產(chǎn)品2", 6);Product p3 = new Product("產(chǎn)品3", 7);Order order = new Order("10001", new Product[]{p1, p2, p3});Iterator iterator = order.createIterator();while (iterator.hasNext()){Product next = (Product) iterator.next();System.out.println(next);}}
}
??同時也可以對比一下不使用迭代器模式
,在客戶端中直接遍歷,體會一下存在哪些弊端:
- 客戶端直接操作 Order 類的內(nèi)部實現(xiàn),如果以后把商品的存儲方式改為其他數(shù)據(jù)結(jié)構(gòu),所有使用 Order 類的代碼都需要修改。
- 遍歷商品數(shù)組的邏輯直接寫在了客戶端,每個需要遍歷商品的地方,都必須重復(fù)寫遍歷邏輯。
- 以及如果需要進(jìn)行不同方式的遍歷,需要修改遍歷邏輯以及所有使用到的客戶端的代碼。
public class Product {private String productName;private double price;public Product(String productName, double price) {this.productName = productName;this.price = price;}public String getProductName() {return productName;}public double getPrice() {return price;}
}public class Order {private String orderId;private Product[] items;public Order(String orderId, Product[] items) {this.orderId = orderId;this.items = items;}public String getOrderId() {return orderId;}public Product[] getItems() {return items;}
}public class Client {public static void main(String[] args) {// 創(chuàng)建產(chǎn)品Product p1 = new Product("Laptop", 1000);Product p2 = new Product("Smartphone", 800);Product p3 = new Product("Headphones", 150);// 創(chuàng)建訂單Product[] products = {p1, p2, p3};Order order = new Order("O1001", products);// 直接在客戶端遍歷商品Product[] items = order.getItems();for (int i = 0; i < items.length; i++) {System.out.println("Product: " + items[i].getProductName() + ", Price: " + items[i].getPrice());}}
}