抽象外觀類的單例化分析與改造
有博友留言問“抽象外觀類是否能設計為單例類?”,為了能夠更全面地回答這個問題,並且為大家在進行物件導向系統設計和實現時提供更多思路,加深對外觀模式和單例模式的理解,特寫此文。
關於外觀模式的基本知識我在此就不介紹了,大家可以參考之前有關外觀模式的幾篇文章。本文所使用的示例程式碼如下(此處採用一種特殊的包含@Stereotype的註釋在原始碼中標註模式角色,目的是在逆向工程生成的UML類圖中能夠自動標註模式角色,該工具已開發完畢):
//@Stereotype Facade:Subsystem
class SubsystemA {
public void method() {
System.out.println("SubsystemA");
}
}
//@Stereotype Facade:Subsystem
class SubsystemB {
public void method() {
System.out.println("SubsystemB");
}
}
//@Stereotype Facade:Subsystem
class SubsystemC {
public void method() {
System.out.println("SubsystemC");
}
}
//@Stereotype Facade:AbstractFacade
abstract class AFacade {
private static AFacade instance = null;
protected AFacade() {}
public abstract void action();
public static AFacade getInstance() {
if (instance == null) {
instance = (AFacade)XMLUtil.getBean();
}
return instance;
}
}
//@Stereotype Facade:ConcreteFacade
class CFacade1 extends AFacade {
public void action() {
SubsystemA a = new SubsystemA();
SubsystemB b = new SubsystemB();
a.method();
b.method();
}
}
//@Stereotype Facade:ConcreteFacade
class CFacade2 extends AFacade {
public void action() {
SubsystemA a = new SubsystemA();
SubsystemC c = new SubsystemC();
a.method();
c.method();
}
}
//Client Class
class Client {
public static void main(String args[]){
AFacade af,af1;
af = AFacade.getInstance();
af1 = AFacade.getInstance();
System.out.println(af == af1);
af.action();
}
}
在上述程式碼中,我們將抽象外觀類設計為單例類(此處只能使用懶漢式單例,大家可以參考前面有關單例模式的文章對懶漢式單例進行進一步改進,解決多執行緒併發訪問的問題),在靜態工廠方法getInstance()中並沒有直接例項化抽象外觀類AFacade(抽象類不能使用new關鍵字直接例項化),而是通過程式碼“instance = (AFacade)XMLUtil.getBean();”(這句程式碼是關鍵)來獲取一個其子類(具體外觀類)的物件。在此處,XMLUtil是一個工具類,程式碼如下:
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil {
//該方法用於從XML配置檔案中提取具體類類名,並返回一個例項物件
public static Object getBean() {
try {
//建立文件物件
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));
//獲取包含類名的文字節點
NodeList nl = doc.getElementsByTagName("className");
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue();
//通過類名生成例項物件並將其返回
Class c=Class.forName(cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
XMLUtil從XML配置檔案(config.xml)中讀取具體外觀類類名字串並反射生成一個外觀物件。我們將具體外觀類類名儲存在XML或properties檔案中,此處使用的是XML格式的配置檔案,程式碼如下(config.xml):
<?xml version="1.0"?>
<config>
<className>CFacade1</className>
</config>
編譯並執行程式,輸出結果如下:
true SubsystemA SubsystemB |
從輸出結果可以得知,在客戶類Client中,af和af1是兩個相同的物件,客戶類與具體外觀類解耦,沒有在客戶端直接指定具體外觀類。如果需要更換具體外觀類,只需修改配置檔案config.xml,例如:
<?xml version="1.0"?>
<config>
<className>CFacade2</className>
</config>
編譯並執行程式,輸出結果如下:
true SubsystemB SubsystemC |
通過對抽象外觀類進行單例化改造,既可以確保抽象外觀類是一個單例類,只能建立其子類的唯一物件,還可以保證系統的靈活性和可維護性,更換或者增加新的具體外觀類無須修改原始碼,符合開閉原則。
在本文中,通過反射生成物件的方式來擴充套件單例類,解決了標準單例模式無法直接通過子類來擴充套件的問題,在需要設計單例類層次結構時可以考慮使用此設計方案,既可確保物件的唯一性又使得系統具有較好的可擴充套件性。
【作者:劉偉 http://blog.csdn.net/lovelion】
相關文章
- 外觀模式及其改進(二):抽象外觀類的引入模式抽象
- Dart - 抽象類的例項化Dart抽象
- 抽象類是不能被例項化的抽象
- 抽象類與介面抽象
- 介面與抽象類抽象
- java多型抽象類例項Java多型抽象
- 類的例項化順序和分析
- java中的抽象類與介面Java抽象
- Java的抽象類與介面理解Java抽象
- 選擇介面還是抽象類?---應用例項說明介面與抽象類的應用場合(區別)抽象
- 單例與序列化單例
- PHP 抽象類繼承抽象類時的注意點PHP 抽象類繼承抽象類時的注意點PHP抽象繼承
- java介面和抽象類的簡單理解Java抽象
- 抽象類能例項化嗎?——口氣很強硬——“不能”(詳解)抽象
- 單例類單例
- PHP中的抽象類、介面與性狀PHP抽象
- Java中的介面與抽象類詳解Java抽象
- Java總結-抽象類與介面Java抽象
- 抽象類與介面的區別抽象
- 關於抽象類與靜態類的初步瞭解抽象
- ThinkPHP6 核心分析之Http 類跟Request類的例項化PHPHTTP
- ThinkPHP6 核心分析(二):Request 類的例項化PHP
- PHP 抽象類繼承抽象類時的注意點PHP抽象繼承
- 抽象類、抽象欄位、抽象方法抽象
- 單例類的總結單例
- 電腦科學中抽象的好處與問題—偽共享例項分析抽象
- 抽象方法和抽象類抽象
- 抽象類和抽象方法抽象
- java單例類Java單例
- 抽象類抽象
- java抽象類與介面——設計模式Java抽象設計模式
- Java抽象類與介面的區別Java抽象
- 介面的行為抽象和抽象類的行為抽象抽象
- java抽象類和抽象方法Java抽象
- Java的抽象類 & 介面Java抽象
- Java中的介面與抽象類設計原則Java抽象
- Java 簡單實現撲克牌抽象類Java抽象
- Java 抽象類Java抽象