如何應用觀察者設計模式重構系統中日誌處理功能實現的程序代碼

2020-12-11 楊教授工作室

軟體項目實訓及課程設計指導——如何應用觀察者設計模式重構系統中的日誌處理功能實現的程序代碼

1、GOF設計模式中的觀察者設計模式

(1)什麼是觀察者設計模式

GOF設計模式中的觀察者設計模式定義了一種解耦「一對多」的依賴關係的編程模式,讓多個不同的觀察者對象同時監聽某一個主題對象。當這個主題對象在「狀態」發生變化時,會通知所有觀察者對象,使這些觀察者對象能夠自動地更新自己的行為以響應主題對象的「狀態」變化。

(2)在示例項目中應用觀察者設計模式的目的

觀察者設計模式本身是對面向對象OOP程序類設計時的「單一職責」設計原則的具體應用——觀察者和被觀察者對象各自完成自己的功能實現方面的不同的職責,兩者不需要緊密耦合和產生複合的職責。

在示例項目銀行帳戶信息管理系統中,作者應用觀察者設計模式的主要目的是希望能夠達到分離「事件的產生者」和「事件的響應者」之間關係的設計目標——也就是將系統中的日誌記錄功能(包括異常日誌和交易日誌)從具體的業務功能實現類或者數據訪問功能的DAO組件類中分離出來。

應用這樣的設計和實現方案,一方面不僅能夠減少系統中的日誌記錄功能實現代碼的「重複」,另一方面也能夠提高軟體應用系統項目在日誌記錄功能實現方面的可擴展性。

讀者可以從作者的另一篇文章《軟體項目實訓及課程設計指導——如何應用策略設計模式的思想設計通用的資料庫連接類》一文中所示的黑體部分的代碼中能夠了解到常規的日誌記錄功能實現所存在的問題——直接將日誌記錄功能實現的代碼插入到資料庫連接ConnectDBBean類的功能實現代碼中,直接包含有日誌處理功能實現的程序代碼。

2、如何在示例項目中應用觀察者設計模式

有關觀察者設計模式的具體編程實現及代碼示例,請讀者參考作者的「J2EE項目實訓——UML及設計模式」一書(如下示圖為該書的封面)中的第10章「典型GOF設計模式及應用」中的有關內容。

作者在下文為讀者介紹如何將觀察者設計模式應用於構建軟體應用系統持久層資料庫連接Connection對象實例的功能實現代碼中以進一步提高軟體應用系統項目中的程序代碼的可擴展性。

下面以重構作者的另一篇文章《軟體項目實訓及課程設計指導——如何應用策略設計模式的思想設計通用的資料庫連接類》一文中的ConnectDBBean類的日誌記錄功能實現過程為示例,說明在軟體應用系統項目中如何具體地應用觀察者設計模式優化程序代碼的功能實現。

3、設計和實現觀察者設計模式中的被觀察者程序類的代碼

在觀察者設計模式中的被觀察者程序類代表需要監控的業務功能類,在本示例中也就是資料庫連接類ConnectDBBean。依據觀察者設計模式中的程序類之間的關係,資料庫連接ConnectDBBean類作為被觀察者類,應該繼承於java.util 包中的Observable類、並利用addObserver方法關聯觀察者類和用notifyObservers方法觸發通知事件。

重構後的完整功能實現的代碼請見如下的程序代碼示例,並請讀者注意其中的黑體部分所標識的語句代碼——對ConnectDBBean類重構後的功能實現程序代碼示例。

package com.px1987.webbank.dao.imple;

import java.sql.*;

import java.util.Observable;

import com.px1987.webbank.config.ClassNameConfig;

import com.px1987.webbank.dao.inter.ConnectDBInterface;

import com.px1987.webbank.exception.WebBankException;

public class ConnectDBBean extends Observableimplements ConnectDBInterface{

String JDBC_DBDriver_ClassName= null;

String JDBC_DSN_URL = null;

String JDBC_dbUserName=null;

String JDBC_dbUserPassWord=null;

private java.sql.Connection con = null;

public ConnectDBBean() throws WebBankException {

/*利用ClassNameConfig實現從屬性文件中獲得與資料庫相關的連接信息 */

JDBC_DBDriver_ClassName =

ClassNameConfig.getProperty("JDBC_DBDriver_ClassName");

JDBC_DSN_URL = ClassNameConfig.getProperty("JDBC_DSN_URL");

JDBC_dbUserName = ClassNameConfig.getProperty("JDBC_dbUserName");

JDBC_dbUserPassWord = ClassNameConfig.getProperty("JDBC_dbUserPassWord");

try {

Class.forName(JDBC_DBDriver_ClassName);

}

catch (java.lang.ClassNotFoundException e) {

intlogImpleKind=

Integer.parseInt(ClassNameConfig.getProperty("logImpleKind"));

this.addObserver(LogInfoFactory.newLogInstance(logImpleKind));this.setChanged();

this.notifyObservers(e);

throw new WebBankException("不能正確地加載JDBC驅動程序");

}

try {

con = DriverManager.getConnection(JDBC_DSN_URL,JDBC_dbUserName,

JDBC_dbUserPassWord);

}

catch (java.sql.SQLException e) {

intlogImpleKind=

Integer.parseInt(ClassNameConfig.getProperty("logImpleKind"));

this.addObserver(LogInfoFactory.newLogInstance(logImpleKind));this.setChanged();

this.notifyObservers(e);

throw new WebBankException("不能正確地連接資料庫"+

"並且出現SQLException");

}

catch (NullPointerException e){

intlogImpleKind=

Integer.parseInt(ClassNameConfig.getProperty("logImpleKind"));

this.addObserver(LogInfoFactory.newLogInstance(logImpleKind));this.setChanged();

this.notifyObservers(e);

throw new WebBankException("無法連接資料庫"+

"並且出現NullPointerException異常");

}

}

public void closeDBCon() throws WebBankException {

try {

con.close();

con = null;

}

catch (SQLException e){

intlogImpleKind=

Integer.parseInt(ClassNameConfig.getProperty("logImpleKind"));

this.addObserver(LogInfoFactory.newLogInstance(logImpleKind));this.setChanged();

this.notifyObservers(e);

throw new WebBankException("不能正確地關閉資料庫連接");

}

}

public Connection getConnection() throws WebBankException {

return con;

}

}

其中的LogInfoFactory類為創建日誌功能實現類對象實例的一個工廠方法模式的工廠類。本工廠類中的產品對象實例的創建方法與標準的GOF工廠設計模式中的產品對象實例的創建方法不同,主要是由於該日誌功能實現類是作為觀察者模式的觀察者類。它返回的是Observer接口類型的對象實例——並實現將觀察者類與被觀察者類相互關聯,而不是日誌功能ExceptionLogInterface接口的實現類LogObserver的對象實例。

當然,為了節省本文章的篇幅,作者在本文中沒有將該LogInfoFactory類的程序代碼一併附錄出。

4、設計和實現觀察者設計模式中的觀察者類的代碼

在觀察者設計模式中的觀察者類代表響應業務功能類的狀態變化的非業務功能類的代碼,在本示例中也就是對資料庫連接類ConnectDBBean中的異常拋出信息進行日誌記錄的功能處理類。

(1)添加觀察者類LogObserver所需要實現的ExceptionLogInterface接口

在MyEclipse開發工具中為本示例項目添加觀察者類LogObserver所需要實現的接口ExceptionLogInterface,該接口所在的包名稱為com.px1987.webbank.util。然後再設計該ExceptionLogInterface接口中的各個功能方法。最後的設計結果請見下圖所示,在該接口中目前只聲明一個logInfo方法——作者對該接口進行了簡化以節省本文的篇幅。

(2)設計觀察者模式中的觀察者類LogObserver

在MyEclipse開發工具中為本項目添加觀察者類LogObserver,該觀察者類一方面需要實現java.util包中的Observer接口,另一方面也需要實現前面的ExceptionLogInterface接口,並且對拋出的異常信息進行觀察監控。

該類所在的包名稱為com.px1987.webbank.util,為了簡化本示例的實現代碼。目前該類的功能實現是基於JDK的Logger類實現具體的日誌功能實現。然後再編程實現該功能類,最後的功能實現代碼請見如下程序代碼示例所示。並請讀者注意其中的黑體部分所標識的語句代碼——觀察者類LogObserver的代碼示例。

package com.px1987.webbank.util;

import java.util.*;

import java.util.logging.*;

public class LogObserver implements Observer, ExceptionLogInterface {

public LogObserver() {

}

public void update(Observable o, Object arg){

String logInfo=o.getClass().getName()+"類出現了"+

arg.getClass().getName()+"類型的異常,並且異常內容為:"+

((Exception)arg).getMessage();

logInfo(logInfo);

}

public void logInfo(String logInfoText) {

Logger logger= Logger.getLogger(this.getClass().getName());

logger.log(Level.INFO, logInfoText);

}

}

5、再執行TestConnectDBBean測試用例類代碼以驗證代碼重構的正確性

為了能夠拋出異常信息以驗證觀察者設計模式重構的正確性,在測試過程中,作者故意關閉MySQL資料庫伺服器。然後再執行TestConnectDBBean測試用例類的程序代碼,此時在控制臺中將出現日誌信息的輸出文字,請見下圖所示示例圖中的紅色提示文字。

根據上圖所示的執行結果,表明採用觀察者設計模式重構的日誌記錄功能實現的代碼是有效的、而且也是正確的。這為軟體應用系統項目以後的日誌記錄功能實現的技術及應用的要求改變提供了良好的靈活性——因為日誌記錄具體的功能實現的程序代碼已經從軟體應用系統的業務功能實現代碼中分離出來了。

再次啟動MySQL資料庫伺服器,並再次執行TestConnectDBBean測試用例類的代碼,此時在控制臺中將不再出現日誌信息的輸出文字,請見下圖示例圖所示。表明觀察者模式中的觀察者類的監控邏輯也是有效的,沒有出現誤判斷的現象。

但希望讀者要注意觀察者設計模式在應用中也仍然還存在有一定的問題,儘管本項目示例採用這樣的方法能夠為日誌處理帶來良好的可擴展性和靈活性,但仍然有一定的代碼重複——下面的程序代碼將重複地出現在不同的功能方法中,最好的實現方法應該是採用面向切面編程AOP技術徹底地進行分離和進一步地減少程序代碼的重複性。

int logImpleKind=Integer.parseInt(ClassNameConfig.getProperty("logImpleKind"));

this.addObserver(LogInfoFactory.newLogInstance(logImpleKind));

/** 注意要設置變化點 */

this.setChanged();

this.notifyObservers(e);

如何應用策略設計模式的思想設計通用的資料庫連接類

如何正確地創建和銷毀軟體應用系統中JDBC資料庫連接對象實例

如何正確地創建和銷毀軟體應用系統中網絡通訊中的Socket對象實例

在程序中如何正確地創建和銷毀軟體應用系統中文件IO流對象實例

課程設計指導——如何應用Java反射技術靈活地創建程序類對象實例

相關焦點

  • 軟體項目實訓及課程設計指導——如何在項目中實現日誌、事務功能
    軟體項目實訓及課程設計指導——如何在J2EE平臺項目中實現交易日誌、事務控制等功能1.1 基於面向切面AOP設計思想的系統架構設計實現交易日誌的應用示例1、面向對象OOP設計中的「開-閉」(OCP,Open-Close Principle)設計原則
  • 如何合理地設計軟體應用系統中數據訪問服務層內的各個功能程序類
    軟體項目實訓及課程設計指導——如何合理地設計數據訪問服務層中的各個功能程序類作者已經在本系列文章《軟體項目實訓及課程設計指導--如何正確地設計J2EE應用系統持久層中的各個組件結構及關係》中為讀者介紹了為什麼要設計和應用數據訪問服務接口的目的及如何設計該接口以真正達到利用數據訪問服務層組件隔離業務處理邏輯和數據訪問操作邏輯的應用效果
  • 如何在Web應用系統表示層開發實現中應用Velocity模板技術
    軟體項目實訓及課程設計指導——如何在Web應用系統表示層開發實現中應用Velocity模板技術1、分離Web表示層的數據處理和展現邏輯的常見的應用技術分離Web表示層的數據處理和展現邏輯是目前企業級的Web應用系統開發中表現層組件開發實現中的基本實現目標。
  • Gof23種設計模式(20)——觀察者模式
    計算機測量與控制,2008.16(2), 141-143,155. [7] 趙德新劉瑾. 設計模式思想及其應用. 天津理工大學學報,2007.23(5), 58-61.[8] 閻小濤劉濤沈為群. 設計模式在航空發動機試驗臺測控系統中的應用. 兵工自動化,2007.26(10), 62-64.[9] 張光會閆新慶. Java2中Observer模式探究.
  • 課程設計指導——如何應用Java反射技術靈活地創建程序類對象實例
    軟體項目實訓及課程設計指導——如何應用Java反射技術靈活地創建程序類的對象實例1、如何應用屬性配置文件實現對系統中的配置信息進行讀寫操作Java中的屬性配置文件主要可以作為軟體應用系統及項目的配置文件,比如許多J2EE的開源框架系統中都提供了屬性配置文件作為該應用框架的對外配置文件
  • java 23種設計模式及其在spring,tomcat,jdk中的應用
    設計模式是前人(一般都是大師)對程序設計經驗的總結,學習並應用設計模式可以使我們開發的項目更加規範、便於擴展和維護,這大概是為什麼設計模式基本是面試必問的原因吧!本文主要內容有四部分:設計原則、設計模式分類、23種設計模式、設計模式應用。設計模式雖多,但重要的、主流開源框架應用較多的往往就那幾個。
  • 結合生產消費者模式實現異步日誌功能
    軟體程序開發過程中,日誌是診斷bug必不可少的功能,日誌功能通常是將每條日誌信息按照一定的格式寫入指定的文件,但是,實時將日誌信息寫入文件,必定耗費時間,對於性能要求比較高的機器來說,可能是無法接受的,並且由於時間差問題可能會帶來無法預料的問題。
  • 軟體項目實訓及課程設計指導——如何實現面向對象的系統架構設計
    因此,在軟體應用系統的設計、開發實現中應該要綜合應用面向對象(OOP)的編程技術和面向方面(AOP)的編程技術。在如下示圖中的程序代碼中夾雜有大量的日誌功能實現的程序代碼,導致日誌功能實現的程序代碼水平地散布在所有對象的層次中----在控制層、業務層和數據訪問層都需要這樣的日誌功能實現,並且而與它所散布到的對象的核心功能毫無關係。
  • 在程序中如何正確地創建和銷毀軟體應用系統中文件IO流對象實例
    Unix作業系統之間在文件管理方面的不同點;並可以實現以相同的程序實現方式處理數據的流動(讀寫)、傳輸(網絡)等方面的功能實現。如下示圖中的程序代碼片段示例體現了Java語言中的IO流編程應用中所需要遵守的基本規則。3、JDK系統庫提供有java.io和java.nio兩種不同的系統程序包如下示圖為JDK系統庫幫助文檔中對Java的核心庫java.io包的功能說明局部截圖。
  • 如何應用策略設計模式分離JDBC資料庫連接中的外部環境信息
    軟體項目實訓及課程設計指導——如何應用策略設計模式分離JDBC資料庫連接中的外部環境信息1、什麼是策略(Strategy)設計模式策略設計模式把「算法」(也就是軟體應用系統中的業務規則或者待實現的功能等)和「環境」(封裝軟體應用系統在實際應用時的場景)相互分離
  • 如何正確地設計J2EE應用系統持久層中的各個組件結構及組件間關係
    當然,也可以應用面向切面AOP編程中所倡導的分離「核心功能」和「輔助功能」程序代碼的設計思想,將事務處理的程序代碼單獨封裝為一個組件類。3、合理地設計和實現軟體應用系統數據持久層中的異常處理功能程序類(1)合理地設計和實現數據持久層中的異常處理功能程序類 由於軟體應用系統數據持久層會涉及大量的對物理資料庫表中的數據的各種操作訪問,而JDBC API中的許多功能方法都有異常拋出的聲明。
  • 觀察者模式--設計模式(一)
    此時可以利用觀察者模式來實現這個功能,這些優質用戶可以訂閱自己感興趣的體育賽事,當現場直播有比分更新或解說員的評論更新時,此時可以通過簡訊發給訂閱這個賽事的優質用戶。同時優質用戶也可以取消訂閱,此時不會收到任何信息。
  • 如何應用GOF設計模式中的創建型模式實現鬆耦合地創建對象實例
    軟體項目實訓及課程設計指導——如何應用GOF設計模式中的創建型模式實現鬆耦合地創建對象實例1、GOF設計模式中的工廠模式在GOF設計模式的劃分中,把與實現對象的實例化相關的模式稱之為「創建型模式」——而其中的工廠模式為創建型模式中的一種具體實現形式。
  • C++設計模式:Observer(觀察者模式)
    假設這樣的需求:我們需要實現一個GUI程序,這個程序用來展示文件分割的進度.但是文件的分割進度可能會有不同的表示,比如我們經常看到的進度處理有:進度條展現百分比展現##號展現我們需要未來能支持到不同的通知模式.代碼架構:主程序(此代碼為了模仿GUI程序中的主窗口):
  • 如何保證軟體應用系統架構設計結果的可擴展性和可重用性(上篇)
    (3)層與層之間應該要相互分離在軟體應用系統的多層架構設計中,一般都倡導將軟體應用系統中的界面顯示功能、業務邏輯處理功能和數據訪問功能完全分離(但按照MVC架構模式的劃分規則,在軟體應用系統的系統架構設計中的業務邏輯層以及數據訪問層中的各個組件都屬於MVC架構模式中的模型組件),而不要在軟體應用系統的界面組件(一般處於系統的表示層
  • 如何實現程序類設計的高內聚和低耦合的系統設計目標(下篇)
    當然,對於面向對象OOP類設計的五大設計原則主要的思想體現、以及設計人員如何運用這些設計原則等具體的內容請讀者閱讀作者的「J2EE項目實訓——UML及設計模式」一書中的第9章「面向對象設計的五大原則」的有關內容。
  • 設計模式之觀察者模式(一)
    前面兩篇已經帶大家走進了設計模式的世界,了解了策略模式,還有基本的OO基礎和OO原則,不知道你是否能讀懂以及了解呢。接下來,我們就要進入第二個模式的學習了,觀察者模式,讓我們來一窺究竟吧。觀察者模式是JDK中使用最多的模式之一,可以幫你的對象知悉情況,不會錯過該對象感興趣的事。對象甚至在運行時可決定是否要繼續被通知。並且後續還會一併介紹一對多關係,以及鬆耦合。
  • 在軟體系統設計中如何降低軟體系統中程序類之間耦合關係(上篇)
    軟體項目實訓及課程設計指導——如何降低軟體系統中程序類之間耦合關係(上篇)1、分離軟體應用系統中各個模塊類的接口定義和對應接口的具體功能實現面向對象程序類設計的五大原則中的「開放-封閉原則」 ( OCP,Open-Close Principle)倡導分離接口的定義和接口的具體功能實現的設計原則
  • 觀察者模式的 Java 實現及應用
    觀察者模式定義觀察者模式定義了對象之間的一對多依賴
  • 觀察者模式解析
    ❝設計模式想必大家都懂一些,不僅能體現平時設計寫代碼的基本功,而且也是面試時的高頻考點。今天來講解學習下 「觀察者模式」。本文在講解具體模式的同時,也會列舉 jdk 以及 常用框架中使用到的地方,幫助大家加深理解。