核心Java設計模式之結構模式
1.概述
結構設計模式是通過識別大型對象結構之間的關係而簡化大型對象結構設計的模式。它們描述了構成類和對象的通用方法,以使它們可以作為解決方案重複使用。
四人幫Gang of Four已經描述了七種這樣的結構方式或模式。在本快速教程中,我們將看到一些示例,這些示例說明了Java中的某些核心庫如何採用它們中的每一個。
2.適配器設計模式
顧名思義,適配器充當中介,將原本不兼容的接口轉換為客戶端期望的接口。
這在我們要採用一個無法修改其源代碼並使其與另一個類一起使用的現有類的情況下很有用。
JDK的收集框架提供了許多適配器模式示例:
List<String> musketeers = Arrays.asList("Athos", "Aramis", "Porthos");
在這裡, Arrays#asList
幫助我們將Array
調整為List
。
I / O框架也廣泛使用此模式。作為示例,讓我們考慮以下代碼段,該代碼段將InputStream
映射到Reader
對象:
InputStreamReader input = new InputStreamReader(new FileInputStream("input.txt"));
3.橋設計模式
橋接模式允許抽象和實現之間的分離,以便它們可以彼此獨立地開發,但仍然具有共存和交互的方式或橋接。
Java中的一個示例是JDBC API。它充當Oracle,MySQL和PostgreSQL等數據庫及其特定實現之間的鏈接。
JDBC API是一組標準接口,例如Driver
, Connection
和ResultSet,
僅舉幾例。這使不同的數據庫供應商可以有各自的實現。
例如,要創建與數據庫的連接,我們會說:
Connection connection = DriverManager.getConnection(url);
在這裡, url
是一個可以代表任何數據庫供應商的字符串。
例如,對於PostgreSQL,我們可能有:
String url = "jdbc:postgresql://localhost/demo";
對於MySQL:
String url = "jdbc:mysql://localhost/demo";
4.組合設計模式
這種模式處理對象的樹狀結構。在這棵樹中,單個對象甚至整個層次結構都以相同的方式處理。用簡單的話來說,此模式以分層的方式排列對象,以便客戶端可以與整個部分無縫地工作。
AWT / Swing中的嵌套容器是核心Java中復合模式用法的一個很好的例子。 java.awt.Container
對象基本上是一個根組件,可以包含其他組件,從而形成嵌套組件的樹形結構。
考慮以下代碼片段:
JTabbedPane pane = new JTabbedPane();
pane.addTab("1", new Container());
pane.addTab("2", new JButton());
pane.addTab("3", new JCheckBox());
此處使用的所有類(即JTabbedPane
, JButton
, JCheckBox
和JFrame
)都是Container
後代。如我們所見,此代碼段在第二行中以處理子節點的方式處理樹或Container
的根。
5.裝飾器設計模式
當我們想要增強對象的行為而不修改原始對象本身時,這種模式就會起作用。這是通過將相同類型的包裝添加到對像以使其承擔附加責任來實現的。
可以在java.io
包中找到此模式最普遍的用法之一:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("test.txt")));
while (bis.available() > 0) {
char c = (char) bis.read();
System.out.println("Char: " + c);
}
在這裡, BufferedInputStream
修飾了FileInputStream
以添加緩衝輸入的功能。值得注意的是,這兩個類都具有InputStream
作為公共祖先。這意味著裝飾的對象和裝飾的對像是同一類型。這是裝飾器模式的明確指示。
6.門面設計模式
根據定義,外牆一詞是指物體的虛假外觀。應用於編程時,它類似地意味著為複雜的對象集提供另一面(或更確切地說,界面) 。
當我們想要簡化或隱藏子系統或框架的複雜性時,這種模式就會發揮作用。
Faces API的ExternalContext
是外觀模式的絕佳示例。它在內部使用HttpServletRequest
, HttpServletResponse
和HttpSession
。基本上,它是一個類,它允許Faces API幸福地意識到其底層應用程序環境。
讓我們看一下**Primefaces**
是如何使用它來編寫HttpResponse
,而實際上並不知道:
protected void writePDFToResponse(ExternalContext externalContext, ByteArrayOutputStream baos, String fileName)
throws IOException, DocumentException {
externalContext.setResponseContentType("application/pdf");
externalContext.setResponseHeader("Expires", "0");
// set more relevant headers
externalContext.setResponseContentLength(baos.size());
externalContext.addResponseCookie(
Constants.DOWNLOAD_COOKIE, "true", Collections.<String, Object>emptyMap());
OutputStream out = externalContext.getResponseOutputStream();
baos.writeTo(out);
// do cleanup
}
正如我們在這裡看到的,我們直接使用ExternalContext
作為外觀來設置響應頭,實際響應和cookie。 HTTPResponse
不在圖片中。
7.flyweight設計模式
flyweight模式通過回收對象來減輕我們對象的重量或內存佔用。換句話說,如果我們有不可變的對象可以共享狀態,那麼按照這種模式,我們可以緩存它們以提高系統性能。
Flyweight可以在Java的所有Number
類中發現。
用於創建任何數據類型的包裝器類的對象的valueOf
方法旨在緩存值,並在需要時返回它們。
例如, Integer
有一個靜態類IntegerCache,
它可以幫助其valueOf
方法始終緩存-128至127範圍內的值:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high) {
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}
8.代理設計模式
這種模式提供了另一個複雜對象的代理或替代。雖然聽起來與立面相似,但是實際上,立面為客戶端提供了與客戶端進行交互的不同界面,這實際上是不同的。對於代理,接口與其隱藏的對象的接口相同。
使用此模式,可以在原始對象創建之前或之後對原始對象執行任何操作。
JDK為代理實現提供了一個現成的java.lang.reflect.Proxy
類:
Foo proxyFoo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class }, handler);
上面的代碼段為接口Foo
創建了一個代理proxyFoo
。
9.結論
在這個簡短的教程中,我們看到了在核心Java中實現的結構設計模式的實際用法。
總而言之,我們簡要定義了七個模式分別代表什麼,然後通過代碼片段逐一理解它們。