日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

适配器和外观模式

發(fā)布時間:2023/12/29 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 适配器和外观模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

適配器模式

說到適配器,我們現(xiàn)實生活中到處都是適配器,其中最容易被大家提起的就是電源適配器。
比如墻上只有一個三孔的插座,而你的手機充電器是兩孔的,這個時候你需要一個,一邊是三腳,一邊提供兩個孔的適配器,來做一次插座接口轉(zhuǎn)換。
實際上,我們常使用的插線板就有這個功能,所以某些場景下它就是適配器。

不兼容的API升級

那么回到面向?qū)ο笾衼?#xff0c;假設(shè)現(xiàn)在你手上已有一個軟件系統(tǒng),集成了廠商的類;現(xiàn)在需要升級廠商到新的類,但是廠商新類提供的API新舊不兼容,如果你不想修改已有的代碼,來解決掉這個升級問題?

審視下當(dāng)前系統(tǒng)有些什么
首先有廠商相關(guān)的類

/*** 原始的廠商API*/ public interface OldVendorApi {void doSomething();}/*** 舊廠商實現(xiàn)*/ public class OldVendorApiImplV1 implements OldVendorApi {@Overridepublic void doSomething() {System.out.println("執(zhí)行舊廠商代碼....");} }

有使用廠商類的代碼

/*** 使用廠商類的客戶端代碼*/ public class YourSystemClient {private OldVendorApi vendorAPI;public YourSystemClient(OldVendorApi vendorAPI) {this.vendorAPI = vendorAPI;}public void callVendorApi(){System.out.println("調(diào)用廠商類api....");vendorAPI.doSomething();} }

能夠正常跑

/*** 測試*/ public class VendorMainV1 {public static void main(String[] args) {YourSystemClient systemClient = new YourSystemClient(new OldVendorApiImplV1());systemClient.callVendorApi();} }

好了,如果現(xiàn)在要升級不兼容的新廠商接口(實際情況下,這種廠商還是很少的),新的api和實現(xiàn)如下

/*** 新的廠商API*/ public interface NewVendorApiV2 {void doSomething2();}/*** 新廠商實現(xiàn)*/ public class NewVendorApiImplV2 implements NewVendorApiV2 {@Overridepublic void doSomething2() {System.out.println("執(zhí)行新的廠商代碼....");} }

我們不修改YourSystemClient類的情況下,可以使用適配器來完成這個升級。
新增適配器

/*** 舊廠商接口適配器,實現(xiàn)舊的接口,實際功能調(diào)用到新的API上*/ public class OldVendorApiAdapter implements OldVendorApi{private NewVendorApiV2 newVendorApi;public OldVendorApiAdapter(NewVendorApiV2 newVendorApi) {this.newVendorApi = newVendorApi;}@Overridepublic void doSomething() {newVendorApi.doSomething2();} }

讓我們的客戶端依賴新的適配器,代碼如下

/*** 測試*/ public class VendorMainV2 {public static void main(String[] args) {OldVendorApiAdapter oldVendorApiAdapter = new OldVendorApiAdapter(new NewVendorApiImplV2());YourSystemClient systemClient = new YourSystemClient(oldVendorApiAdapter);systemClient.callVendorApi();} }

這樣,通過傳入適配器類,就實現(xiàn)了,不修改代碼,通過增加代碼來實現(xiàn)升級。

按照慣例,看下UML圖

火雞偽裝鴨子

再看一個示例,看看如何讓火雞來偽裝成一個鴨子,混到鴨子中去的。
首先我們先吧鴨子接口和實現(xiàn),火雞接口和實現(xiàn)提供出來。

/*** 鴨子接口*/ public interface Duck {void quack();void fly(); }/*** 綠頭鴨*/ public class MallardDuck implements Duck {@Overridepublic void quack() {System.out.println("呱呱呱的叫");}@Overridepublic void fly() {System.out.println("飛30米...");} }/*** 火雞接口*/ public interface Turkey {void gobble();void fly(); }/*** 野生火雞*/ public class WildTurkey implements Turkey{@Overridepublic void gobble() {System.out.println("咕咕的叫");}@Overridepublic void fly() {System.out.println("飛了10米");} }

接下來,使用一個適配器,通過它來將火雞偽裝成鴨子

/*** 火雞適配器-將火雞適配成鴨子*/ public class TurkeyAdapter implements Duck {Turkey turkey;public TurkeyAdapter(Turkey turkey) {this.turkey = turkey;}@Overridepublic void quack() {turkey.gobble();}@Overridepublic void fly() {for (int i = 0; i < 3; i++) {turkey.fly();}} }

測試偽裝

/*** 測試*/ public class DuckMain {public static void main(String[] args) {Duck duck = new MallardDuck();duck.quack();duck.fly();System.out.println();duck = new TurkeyAdapter(new WildTurkey());duck.quack();duck.fly();} }

看下UML圖

定義

適配者模式將一個類的接口,裝換為客戶希望的另外一個接口,讓原本不兼容的類可以合作無間

我們用代碼來實現(xiàn)一波
目標(biāo)接口(客戶希望的接口)

/*** 目標(biāo)接口*/ public interface Target {void request(); }

不能夠直接兼容的被適配者

/*** 被適配者*/ public class Adaptee {public void specialRequest(){System.out.println("被適配者具體工作....");} }

做接口轉(zhuǎn)換的適配器類

/*** 適配器,實現(xiàn)目標(biāo)接口,將請求轉(zhuǎn)發(fā)給被適配者*/ public class Adapter implements Target {private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specialRequest();} }

客戶端類

/*** 客戶*/ public class Client {private Target target;public Client(Target target) {this.target = target;}public void doSomething(){target.request();} }

測試

/*** 測試*/ public class AdapterMain {public static void main(String[] args) {Adapter adapter = new Adapter(new Adaptee());Client client = new Client(adapter);client.doSomething();} }

可以看到,通過適配器類的接口轉(zhuǎn)換和轉(zhuǎn)發(fā),讓客戶類通過目標(biāo)接口,使用了原本不能兼容的被適配者類的能力。

看看UML圖。

我們前面學(xué)到了裝飾者模式,他們都是通過加一層包裝來實現(xiàn)客戶也具體工作類之間的解耦。
他們的區(qū)別是什么?

適配者模式是通過包裝來提供接口轉(zhuǎn)換,而裝飾者通過包裝來動態(tài)的提供新的能力,他們的意圖不同。

擴展示例

https://www.c-sharpcorner.com/UploadFile/b7dc95/adapter-design-pattern-demystified/
這是一個只支持USB接口的筆記本電腦,要使用老的PS/2接口鼠標(biāo)時,使用適配器的例子。

外觀模式

你已經(jīng)知道適配器模式是如何將一個接口轉(zhuǎn)換為成另一個符合客戶預(yù)期的接口,達到兼容的目的;
另一個裝換接口的模式,其目的是為了簡化接口,這個模式叫外觀模式,它將一個或者數(shù)個復(fù)雜的接口隱藏在背后,留出干凈美好的外觀。

裝房子

通過前面的項目中,攢了些錢,在加上父母贊助和向朋友借錢,買了一套房子,現(xiàn)在交房了準(zhǔn)備裝修,通過向朋友了解了下,有兩種方式。
一種方式是自己買材料,自己聯(lián)系工人(泥水工、木工、電工),自己檢驗,所有的事情親力親為,但相對省錢。
另一種方式是,通過裝修公司,所有的事情整包給裝修公司,你只需要交錢、驗收就好了(當(dāng)然實際情況可沒有這么簡單,中間還是有很多溝通和交互的)

那么我們來分別用代碼實現(xiàn)看看。
首先,將裝修中要打交道的角色創(chuàng)建出來。

/*** 地磚商人*/ public class 地磚商人 {public void 購買地磚(){System.out.println("從地磚商人購買地磚");} }/*** 水泥商人*/ public class 水泥商人 {public void 購買水泥(){System.out.println("從水泥商人購買水泥");} }/*** 石材商人*/ public class 石材商人 {public void 購買石材(){System.out.println("從石材商人購買石材");} }/*** 泥水工*/ public class 泥水工 {public void 鋪地磚(){System.out.println("泥水工鋪地磚");} }/*** 木工*/ public class 木工 {public void 做柜子(){System.out.println("木工做柜子");} }/*** 電工*/ public class 電工 {public void 鋪電線(){System.out.println("電工鋪電線");} }

V1版

V1版使用親力親為的這種方式。

/*** 親力親為的新房主人,要和所有人打交道,好累。*/ public class 新房主人V1 {public void 裝修房子(){地磚商人 地磚商人 = new 地磚商人();地磚商人.購買地磚();水泥商人 水泥商人 = new 水泥商人();水泥商人.購買水泥();石材商人 石材商人 = new 石材商人();石材商人.購買石材();泥水工 泥水工 = new 泥水工();泥水工.鋪地磚();木工 木工 = new 木工();木工.做柜子();電工 電工 = new 電工();電工.鋪電線();} }

測試走起

/*** 測試*/ public class HouseDecorateMainV1 {public static void main(String[] args) {新房主人V1 新房主人 = new 新房主人V1();新房主人.裝修房子();} }

可以看出,主人為了省錢還是很拼的。

V2版

接下來看看V2的做法,通過裝修公司來裝修新房

/*** 代替裝修業(yè)主和各個角色打交道,臟活累活都有我來做吧。*/ public class 裝修公司 {public void 裝修新房(){地磚商人 地磚商人 = new 地磚商人();地磚商人.購買地磚();水泥商人 水泥商人 = new 水泥商人();水泥商人.購買水泥();石材商人 石材商人 = new 石材商人();石材商人.購買石材();泥水工 泥水工 = new 泥水工();泥水工.鋪地磚();木工 木工 = new 木工();木工.做柜子();電工 電工 = new 電工();電工.鋪電線();} }

V2版的新房主人就之和裝修公司打交道,世界都變得美好起來了。

/*** 親力親為的新房主人,要和所有人打交道,好累。*/ public class 新房主人V2 {public void 裝修房子(){裝修公司 兄弟裝修公司 = new 裝修公司();兄弟裝修公司.裝修新房();} }

測試

/*** 測試*/ public class HouseDecorateMainV2 {public static void main(String[] args) {新房主人V2 新房主人 = new 新房主人V2();新房主人.裝修房子();} }

可以看出,代碼是一樣,不過V2中在新房主人和各個商人/工人中間加入一層,這一層聚合了和各個角色交互,對于裝房的人來說,簡化了裝房的過程。

看下V2的UML圖

定義

V2版的實現(xiàn)就用到了外觀模式,也叫門面模式,外觀模式提供了一個統(tǒng)一的接口,用來訪問子系統(tǒng)中的一群接口,簡化子系統(tǒng)的使用。
當(dāng)然,你可以繞過這個簡單的外觀,而直接使用子系統(tǒng)的接口,做精細化控制。

代碼來實現(xiàn)一波定義。

/*** 子系統(tǒng)A*/ public class SubsystemA {public void doSpecial(){System.out.println("子系統(tǒng)A執(zhí)行特殊的方法....");} }/*** 子系統(tǒng)B*/ public class SubsystemB {public void doSpecial(){System.out.println("子系統(tǒng)B執(zhí)行特殊的方法....");} }/*** 子系統(tǒng)C*/ public class SubsystemC {public void doSpecial(){System.out.println("子系統(tǒng)C執(zhí)行特殊的方法....");} }

接下來,用一個門面來聚合子系統(tǒng)的能力,提供聚合能力

/*** 門面,提供簡單干凈的對外接口*/ public class SystemFacade {public void doSomeSpecialThing(){SubsystemA subsystemA = new SubsystemA();subsystemA.doSpecial();SubsystemB subsystemB = new SubsystemB();subsystemB.doSpecial();SubsystemC subsystemC = new SubsystemC();subsystemC.doSpecial();} }

這樣,客戶就可以非常容易的使用門面來獲取聚合的能力了

/*** 使用門面的客戶*/ public class Client {public void doSomeThing(){SystemFacade systemFacade = new SystemFacade();systemFacade.doSomeSpecialThing();}public static void main(String[] args) {new Client().doSomeThing();} }

觀察UML圖

擴展示例

為了加深理解,我們來看下一個電商庫存的例子。
同樣,先把子系統(tǒng)構(gòu)建起來,就是實際干活的如庫存管理、校驗管理、費用計算、支付、物流這些子系統(tǒng)。
各個子系統(tǒng),貼出兩個子系統(tǒng)的代碼,其他子系統(tǒng)類似。

/*** 庫存接口*/ public interface IInventory {void update(int productId); }/*** 庫存管理*/ public class InventoryManager implements IInventory {@Overridepublic void update(int productId) {String msg = "Product# " + productId +" is subtracted from store's inventory";System.out.println(msg);} }/*** 訂單校驗接口*/ public interface IOrderVerify {boolean verifyShippingAddress(int pincode); }/*** 訂單檢驗管理*/ public class OrderVerificationManager implements IOrderVerify {@Overridepublic boolean verifyShippingAddress(int pincode) {System.out.println("The product can be shipped to the pincode "+ pincode);return true;} }

如果沒使用外觀時,客戶直接使用子系統(tǒng),代碼會長成下面這個樣子

/*** 沒有使用外觀時的客戶長這個樣子*/ public class NoFacadeMain {public static void main(String[] args) {// Creating the Order/Product detailsOrderDetails orderDetails = new OrderDetails("Java Design Pattern book","Simplified book on design patterns in Java",500, 10, "Street No 1", "Educational Area", 1212,"8811123456");// Updating the inventory.IInventory inventory = new InventoryManager();inventory.update(orderDetails.getProductNo());// verifying various details for the order such as the shipping address.IOrderVerify orderVerify = new OrderVerificationManager();orderVerify.verifyShippingAddress(orderDetails.getPinCode());// Calculating the final cost after applying various discounts.ICosting costManager = new CostManager();orderDetails.setPrice(costManager.applyDiscount(orderDetails.getPrice(),orderDetails.getDiscountPercent()));// Going through various steps if payment gateway like card verification,// charging from the card.IPaymentGateway paymentGateway = new PaymentGatewayManager();paymentGateway.verifyCardDetails(orderDetails.getCardNo());paymentGateway.processPayment(orderDetails.getCardNo(), orderDetails.getPrice());// Completing the order by providing logistics.ILogistics logistics = new LogisticsManager();String shippingAddress = String.format("%s, %s - %d",orderDetails.getAddressLine1(),orderDetails.getAddressLine2(),orderDetails.getPinCode());logistics.shipProducts(orderDetails.getProductName(), shippingAddress);} }

但是如果引入了外觀后,客戶會長成:

/*** 使用外觀后的客戶長這個樣子*/ public class FacadeMain {public static void main(String[] args) {// Creating the Order/Product detailsOrderDetails orderDetails = new OrderDetails("Java Design Pattern book","Simplified book on design patterns in Java",500, 10, "Street No 1", "Educational Area", 1212,"8811123456");// Using FacadeOnlineShoppingFacade facade = new OnlineShoppingFacade();facade.finalizeOrder(orderDetails);} }

其中的外觀:

/*** 購物外觀*/ public class OnlineShoppingFacade {IInventory inventory = new InventoryManager();IOrderVerify orderVerify = new OrderVerificationManager();ICosting costManager = new CostManager();IPaymentGateway paymentGateway = new PaymentGatewayManager();ILogistics logistics = new LogisticsManager();public void finalizeOrder(OrderDetails orderDetails) {inventory.update(orderDetails.getProductNo());orderVerify.verifyShippingAddress(orderDetails.getPinCode());orderDetails.setPrice(costManager.applyDiscount(orderDetails.getPrice(),orderDetails.getDiscountPercent()));paymentGateway.verifyCardDetails(orderDetails.getCardNo());paymentGateway.processPayment(orderDetails.getCardNo(), orderDetails.getPrice());String shippingAddress = String.format("%s, %s - %d",orderDetails.getAddressLine1(),orderDetails.getAddressLine2(),orderDetails.getPinCode());logistics.shipProducts(orderDetails.getCardNo(), shippingAddress);} }

該示例代碼參考: https://www.codeproject.com/Articles/767154/Facade-Design-Pattern-Csharp

源碼

https://gitee.com/cq-laozhou/design-pattern

總結(jié)

以上是生活随笔為你收集整理的适配器和外观模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。