裝飾器模式介紹和典型實現

裝飾器模式(Decorator Pattern)是一種結構型設計模式,它允許你通過將對象放入包含行為的特殊封裝對象中來為原對象添加新的功能。裝飾器模式的主要優點是可以在運行時動態地添加功能,而不需要修改原對象的代碼。這使得代碼更加靈活和可擴展。

裝飾器模式的說明

角色
  1. Component(組件)

    • 定義了對象的接口,可以給這些對象動態地添加職責。
    • 可以是抽象類或接口。
  2. ConcreteComponent(具體組件)

    • 實現了 Component 接口,定義了具體的業務邏輯。
  3. Decorator(裝飾器)

    • 也實現了 Component 接口,但其主要職責是為組件動態地添加功能。
    • 通常包含一個對 Component 的引用,以便調用被裝飾對象的方法。
  4. ConcreteDecorator(具體裝飾器)

    • 實現了 Decorator,添加了具體的功能。
  5. Client(客戶端)

    • 通過 Component 接口操作對象,無需關心對象的具體類型。

經典框架中的實現案例

1. Java I/O 框架

Java I/O 框架中的 InputStreamOutputStream 類及其子類(如 BufferedInputStreamDataInputStream 等)是裝飾器模式的經典應用。

  • Component(組件)InputStreamOutputStream
  • ConcreteComponent(具體組件)FileInputStreamFileOutputStream
  • Decorator(裝飾器)BufferedInputStreamDataInputStreamBufferedOutputStreamDataOutputStream
  • ConcreteDecorator(具體裝飾器)BufferedInputStreamDataInputStreamInputStream 添加了緩沖和數據讀取功能;BufferedOutputStreamDataOutputStreamOutputStream 添加了緩沖和數據寫入功能。
import java.io.*;public class JavaIOCompositeExample {public static void main(String[] args) {try {// 創建 FileInputStreamInputStream fileInputStream = new FileInputStream("input.txt");// 創建 BufferedInputStreamInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);// 創建 DataInputStreamInputStream dataInputStream = new DataInputStream(bufferedInputStream);// 讀取數據int data;while ((data = dataInputStream.read()) != -1) {System.out.print((char) data);}// 關閉流dataInputStream.close();// 創建 FileOutputStreamOutputStream fileOutputStream = new FileOutputStream("output.txt");// 創建 BufferedOutputStreamOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);// 創建 DataOutputStreamOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream);// 寫入數據dataOutputStream.writeBytes("Hello, World!");// 關閉流dataOutputStream.close();} catch (IOException e) {e.printStackTrace();}}
}

在這個例子中:

  • FileInputStreamFileOutputStream 是具體組件,提供基本的文件讀寫功能。
  • BufferedInputStreamBufferedOutputStream 是裝飾器,為文件讀寫添加了緩沖功能。
  • DataInputStreamDataOutputStream 是具體裝飾器,為文件讀寫添加了數據讀寫功能。
  • 客戶端代碼通過裝飾器鏈來讀寫文件,而不需要關心具體的功能實現。
2. Spring AOP

Spring AOP(Aspect-Oriented Programming)框架中的切面(Aspect)和通知(Advice)可以看作是裝飾器模式的應用。通過 AOP,可以在運行時動態地為方法添加額外的功能,如日志記錄、事務管理等。

  • Component(組件):業務邏輯方法。
  • ConcreteComponent(具體組件):具體的業務邏輯實現。
  • Decorator(裝飾器):切面(Aspect)。
  • ConcreteDecorator(具體裝飾器):通知(Advice),如 @Before@After@Around 等。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;@Aspect
public class LoggingAspect {@Before("execution(* com.example.service.MyService.doSomething(..))")public void logBefore() {System.out.println("Logging before method execution");}
}public class MyService {public void doSomething() {System.out.println("Doing something in MyService");}
}public class SpringAOPCompositeExample {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(MyService.class, LoggingAspect.class);context.refresh();MyService myService = context.getBean(MyService.class);myService.doSomething();context.close();}
}

在這個例子中:

  • MyService 是具體組件,定義了具體的業務邏輯。
  • LoggingAspect 是裝飾器,通過 @Before 注解為 MyServicedoSomething 方法添加了日志記錄功能。
  • 客戶端代碼通過 Spring 容器獲取 MyService 的實例,并調用其方法,而不需要關心日志記錄的具體實現。

3. MyBatis 框架

MyBatis 框架中的 Interceptor 機制也可以看作是裝飾器模式的應用。通過 Interceptor,可以在 SQL 執行前后添加額外的邏輯,如緩存、日志記錄等。

  • Component(組件)Executor 接口。
  • ConcreteComponent(具體組件)BaseExecutor 類。
  • Decorator(裝飾器)Interceptor 接口。
  • ConcreteDecorator(具體裝飾器):具體的 Interceptor 實現。
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.plugin.*;import java.util.Properties;@Intercepts({@Signature(type = Executor.class, method = "update", args = {String.class, Object.class})})
public class MyInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("Intercepting before update method execution");Object result = invocation.proceed();System.out.println("Intercepting after update method execution");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 設置屬性}
}public class MyBatisCompositeExample {public static void main(String[] args) {// 創建 SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = MyBatisCompositeExample.class.getClassLoader().getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 注冊 InterceptorsqlSessionFactory.getConfiguration().addInterceptor(new MyInterceptor());// 獲取 SqlSessiontry (SqlSession session = sqlSessionFactory.openSession()) {// 獲取 MapperUserMapper userMapper = session.getMapper(UserMapper.class);// 執行更新操作userMapper.updateUser(new User(1, "John Doe"));}}
}// User 類
public class User {private int id;private String name;public User(int id, String name) {this.id = id;this.name = name;}// Getters and Setters
}// UserMapper 接口
public interface UserMapper {void updateUser(User user);
}// mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mydb"/><property name="username" value="root"/><property name="password" value="password"/></dataSource></environment></environments><mappers><mapper resource="UserMapper.xml"/></mappers>
</configuration>// UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><update id="updateUser" parameterType="com.example.model.User">UPDATE usersSET name = #{name}WHERE id = #{id}</update>
</mapper>

在這個例子中:

  • Executor 是組件,負責執行 SQL 語句。
  • BaseExecutor 是具體組件,提供了基本的 SQL 執行功能。
  • MyInterceptor 是具體裝飾器,通過 @Intercepts 注解為 Executorupdate 方法添加了日志記錄功能。
  • 客戶端代碼通過 SqlSessionFactory 獲取 SqlSession,再通過 SqlSession 獲取 UserMapper,并調用其方法,而不需要關心日志記錄的具體實現。

運行結果

Intercepting before update method execution
Doing something in MyService
Intercepting after update method execution

解釋

  1. Component(組件)

    • Executor 接口定義了執行 SQL 語句的方法。
    • BaseExecutor 類實現了 Executor 接口,提供了基本的 SQL 執行功能。
  2. Decorator(裝飾器)

    • Interceptor 接口定義了攔截器的方法。
    • MyInterceptor 類實現了 Interceptor 接口,添加了日志記錄功能。
  3. ConcreteDecorator(具體裝飾器)

    • MyInterceptor 通過 intercept 方法在 SQL 執行前后添加日志記錄功能。
  4. Client(客戶端)

    • 客戶端代碼通過 SqlSessionFactory 獲取 SqlSession,再通過 SqlSession 獲取 UserMapper,并調用其方法,而不需要關心日志記錄的具體實現。

總結

  1. Java I/O 框架

    • 通過 InputStreamOutputStream 的裝飾器(如 BufferedInputStreamDataInputStream)動態地添加功能,使得 I/O 操作更加靈活和高效。
  2. Spring AOP

    • 通過切面(Aspect)和通知(Advice)為方法動態地添加額外的功能,如日志記錄、事務管理等,使得業務邏輯更加清晰和模塊化。
  3. MyBatis 框架

    • 通過 Interceptor 機制為 SQL 執行動態地添加額外的功能,如日志記錄、緩存等,使得 SQL 操作更加靈活和可擴展。

通過這些經典實現,可以看到裝飾器模式在實際應用中的強大之處,它不僅簡化了客戶端代碼,還提高了系統的可維護性和擴展性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/74789.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/74789.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/74789.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【 <二> 丹方改良:Spring 時代的 JavaWeb】之 Spring Boot 中的日志管理:Logback 的集成

<前文回顧> 點擊此處查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、開篇整…

神經網絡知識點整理

目錄 ?一、深度學習基礎與流程 二、神經網絡基礎組件 三、卷積神經網絡&#xff08;CNN&#xff09;?編輯 四、循環神經網絡&#xff08;RNN&#xff09;與LSTM 五、優化技巧與調參 六、應用場景與前沿?編輯 七、總結與展望?編輯 一、深度學習基礎與流程 機器學習流…

【sql優化】where 1=1

文章目錄 where 11問題描述錯誤實現正確實現性能對比測試 where 11 問題描述 在動態 SQL 拼接場景中&#xff0c;開發者常使用 WHERE 11 簡化條件拼接邏輯&#xff08;避免處理首個條件的 AND&#xff09;。理論上&#xff0c;數據庫優化器會忽略 11&#xff0c;但字符串拼接…

車載以太網網絡測試 -24【SOME/IP概述】

目錄 1 摘要2 車載SOME/IP 概述2.1發展背景以及應用2.1.1車載 SOME/IP 背景2.1.2 車載 SOME/IP 應用場景 2.3 什么是SOME/IP2.3.1 SOME/IP定義2.3.2 SOME/IP在協議棧中的位置 3 SOA是什么4 SOME/IP主要功能5 SOME/IP標準 1 摘要 本文主要介紹SOME/IP的背景以及在車載行業的發展…

vue3中,route4,獲取當前頁面路由的問題

首先應用場景如下&#xff1a; 在main.js里面&#xff0c;引入的是路由的配置文件&#xff0c;如下&#xff1a; import {router} from /router; app.use(router); 路由配置文件router.js如下&#xff1a; import { createRouter, createWebHistory } from vue-router; imp…

ip改變導致的數據庫連接不上

前言 需要用到路由器&#xff0c;所以先把家里的路由器給拆了先用著。新的路由器到了之后&#xff0c;更換上新的路由器之后&#xff0c;調用到服務會有報錯&#xff0c;記錄一下更換路由器之后ip重新分配服務可能會報的錯. 進一步可以看到有關網路在服務當中的影響。 正文 …

Chrome 開發環境快速屏蔽 CORS 跨域限制!

Chrome 開發環境快速屏蔽 CORS 跨域限制【詳細教程】 ? 為什么需要臨時屏蔽 CORS&#xff1f; 在前后端開發過程中&#xff0c;我們經常會遇到 跨域請求被瀏覽器攔截 的問題。例如&#xff0c;你在 http://localhost:3000 調用 https://api.example.com 時&#xff0c;可能會…

【力扣hot100題】(009)和為K的子數組

還是太菜了&#xff08;我&#xff09;&#xff0c;寫了半天滑動窗口&#xff0c;然后看了答案又寫了半天時間超限…… 總之就是記錄每前n個子串的和&#xff0c;然后使用hash存儲和為某個值出現的次數&#xff0c;每次求得新和就看看是否存在前面新和-k的字符&#xff0c;有的…

使用 rsync 進行服務器文件同步與優化

使用 Rsync 工具在兩臺 Linux 服務器之間同步文件 Rsync 是一種高效的文件同步工具&#xff0c;它可以在本地或遠程服務器之間同步文件和目錄。Rsync 通過僅傳輸文件的變化部分來減少數據傳輸量&#xff0c;因此特別適合用于定期備份或同步大量數據。本文將詳細介紹如何將 A 服…

卷積神經網絡 - 微步卷積、空洞卷積

一、微步卷積 微步卷積&#xff08;Fractionally Strided Convolution&#xff09;&#xff0c;通常也稱為轉置卷積&#xff08;Transposed Convolution&#xff09;或反卷積&#xff08;Deconvolution&#xff09;&#xff0c;是深度學習&#xff08;尤其是卷積神經網絡&…

詳解java體系實用知識總結

0.java技術能力框架 基礎模塊應用模塊綜合模塊技術崗位與面試流程常用工具集系統架構設計計算機基礎常用框架微服務架構jvm原理緩存容器化多線程隊列云計算&#xff08;阿里云/aws&#xff09;設計模式數據庫數據結構與算法 1.常用設計模式與應用場景 工廠模式&#xff1a;s…

設計模式之創建型5種

設計模式 為什么設計模式是23種創建型 對象創建為什么設計模式是23種 設計模式之所以被歸納為23種,而非其他數量,源于GoF(Gang of Four)在1994年的系統性總結和分類。這一數量的確定并非偶然,而是基于以下核心原因: 他們遵循“大三律”(Rule of Three),即只有經過三個…

Oracle 23ai Vector Search 系列之2 ONNX(Open Neural Network Exchange)

文章目錄 Oracle 23ai Vector Search 系列之2 ONNX(Open Neural Network Exchange)ONNX基本概念ONNX(Open Neural Network Exchange)ONNX Runtime ONNX Runtime 在Oracle數據庫中的集成參考 Oracle 23ai Vector Search 系列之2 ONNX(Open Neural Network Exchange) 我們在看【…

統一語言學習范式

摘要 現有的預訓練模型通常針對特定類別的問題。迄今為止&#xff0c;關于何種架構和預訓練設置應為最佳似乎仍未達成共識。本文提出了一個統一的框架&#xff0c;用于預訓練在多種數據集和設置中普遍有效的模型。我們首先將架構原型與預訓練目標這兩個常被混為一談的概念進行…

Flutter項目升級到指定版本的詳細步驟指南

一、升級前的準備工作 備份項目 使用Git提交當前所有修改&#xff1a;git commit -am "Pre-upgrade backup"或直接復制項目文件夾 查看當前環境信息 flutter --version flutter doctor二、升級Flutter SDK到指定版本 方法1&#xff1a;通過版本管理工具升級&#x…

22、web前端開發之html5(三)

六. 離線存儲與緩存 在網絡環境不穩定或需要優化資源加載速度的場景下&#xff0c;離線存儲與緩存技術顯得尤為重要。HTML5引入了多種離線存儲和緩存機制&#xff0c;幫助開發者提升用戶體驗。本節將詳細介紹Application Cache、localStorage、sessionStorage以及IndexedDB等技…

用HTML和CSS生成炫光動畫卡片

這個效果結合了漸變、旋轉和懸浮效果的炫酷動畫示例&#xff0c;使用HTML和CSS實現。 一、效果 二、實現 代碼如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport&quo…

【嵌入式學習2】數組

目錄 ## 數組概念 ## 數組使用 ## 數組初始化 ## 數組名 ## 數組長度 ## 數組相關題目 1、找最大值 2、逆置 ## 數組和指針 指針加整數的含義 ## 指針數組 ## 數組名做函數參數 ## 函數參數傳遞數組 1、在函數內部 2. 在函數外部 ## 多維數組 使用下標訪問 #…

C++中的判斷與循環

一.if判斷語句 1.程序中的判斷&#xff1a; if (要執行的判斷&#xff0c;最后的返回值要是bool型的數據) {如果為真&#xff0c;要執行的代碼段; } #include"iostream" using namespace std;int main() {int ans;cin >> ans;if (ans > 1000) {cout <…

前端開發中生成網站的favicon.ico文件的軟件推薦及使用方法

日常網站開發中&#xff0c;我們經常需要生成網站的favicon.ico文件&#xff0c;今天我在這里來推薦幾個編輯.ico(也可將圖片格式轉化為.ico)圖片&#xff0c;而且免費的那軟件&#xff1a; GIMP&#xff1a;一個功能強大的開源圖像編輯軟件&#xff0c;支持多種文件格式&#…