設計模式--Adapter模式
介面卡模式將現有介面轉化為客戶類所期望的介面,實現了對現有類的複用,它是一種使用頻率非常高的設計模式,在軟體開發中得以廣泛應用,在Spring等開源框架、驅動程式設計(如JDBC中的資料庫驅動程式)中也使用了介面卡模式。
1. 主要優點
無論是物件介面卡模式還是類介面卡模式都具有如下優點:
(1) 將目標類和適配者類解耦,通過引入一個介面卡類來重用現有的適配者類,無須修改原有結構。
(2)增加了類的透明性和複用性,將具體的業務實現過程封裝在適配者類中,對於客戶端類而言是透明的,而且提高了適配者的複用性,同一個適配者類可以在多個不同的系統中複用。
(3)
具體來說,類介面卡模式還有如下優點:
由於介面卡類是適配者類的子類,因此可以在介面卡類中置換一些適配者的方法,使得介面卡的靈活性更強。
物件介面卡模式還有如下優點:
(1) 一個物件介面卡可以把多個不同的適配者適配到同一個目標;
(2) 可以適配一個適配者的子類,由於介面卡和適配者之間是關聯關係,根據“里氏代換原則”,適配者的子類也可通過該介面卡進行適配。
2. 主要缺點
類介面卡模式
(1) 對於Java、C#等不支援多重類繼承的語言,一次最多隻能適配一個適配者類,不能同時適配多個適配者;
(2) 適配者類不能為最終類,如在Java中不能為final類,C#中不能為sealed類;
(3) 在Java、C#等語言中,類介面卡模式中的目標抽象類只能為介面,不能為類,其使用有一定的侷限性。
物件介面卡模式的缺點如下:
與類介面卡模式相比,要在介面卡中置換適配者類的某些方法比較麻煩。如果一定要置換掉適配者類的一個或多個方法,可以先做一個適配者類的子類,將適配者類的方法置換掉,然後再把適配者類的子類當做真正的適配者進行適配,實現過程較為複雜。
3. 適用場景
在以下情況下可以考慮使用介面卡模式:
(1) 系統需要使用一些現有的類,而這些類的介面(如方法名)不符合系統的需要,甚至沒有這些類的原始碼。
(2) 想建立一個可以重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。
直接程式碼:
demo1:
public class Banner {
private String string;
public Banner(String string) {
this.string = string;
}
public void showWithParen() {
System.out.println("(" + string + ")");
}
public void showWithAster() {
System.out.println("*" + string + "*");
}
}
public interface Print {
public abstract void printWeak();
public abstract void printStrong();
}
public class PrintBanner extends Banner implements Print {
public PrintBanner(String string) {
super(string);
}
public void printWeak() {
showWithParen();
}
public void printStrong() {
showWithAster();
}
}
public class Main {
public static void main(String[] args) {
Print p = new PrintBanner("Hello");
p.printWeak();
p.printStrong();
}
}
稍微變一下;
demo2:
public class Banner {
private String string;
public Banner(String string) {
this.string = string;
}
public void showWithParen() {
System.out.println("(" + string + ")");
}
public void showWithAster() {
System.out.println("*" + string + "*");
}
}
public abstract class Print {
public abstract void printWeak();
public abstract void printStrong();
}
public class PrintBanner extends Print {
private Banner banner;
public PrintBanner(String string) {
this.banner = new Banner(string);
}
public void printWeak() {
banner.showWithParen();
}
public void printStrong() {
banner.showWithAster();
}
}
public class Main {
public static void main(String[] args) {
Print p = new PrintBanner("Hello");
p.printWeak();
p.printStrong();
}
}
demo3:
import java.io.*;
public interface FileIO {
public void readFromFile(String filename) throws IOException;
public void writeToFile(String filename) throws IOException;
public void setValue(String key, String value);
public String getValue(String key);
}
import java.io.*;
import java.util.*;
public class FileProperties extends Properties implements FileIO {
public void readFromFile(String filename) throws IOException {
load(new FileInputStream(filename));
}
public void writeToFile(String filename) throws IOException {
store(new FileOutputStream(filename), "written by FileProperties");
}
public void setValue(String key, String value) {
setProperty(key, value);
}
public String getValue(String key) {
return getProperty(key, "");
}
}
import java.io.*;
public class Main {
public static void main(String[] args) {
FileIO f = new FileProperties();
try {
f.readFromFile("file.txt");
f.setValue("year", "2004");
f.setValue("month", "4");
f.setValue("day", "21");
f.writeToFile("newfile.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}