Java設(shè)計(jì)模式之裝飾模式詳解
一、裝飾模式引入例子
一個(gè)快餐店計(jì)算價(jià)格問題舉例:
快餐店有炒面、炒飯這些快餐,可以額外附加雞蛋、火腿、培根這些配菜,加配菜需要額外加錢,并且每個(gè)配菜的價(jià)錢不一樣,計(jì)算快餐價(jià)格如何實(shí)現(xiàn)?
1.1 一般設(shè)計(jì)

1.2 使用繼承方式的一般設(shè)計(jì)存在的問題
橫向擴(kuò)展性不好:如果要再加一種配料(火腿腸),我們就會(huì)發(fā)現(xiàn)需要給FriedRice和FriedNoodles分別定義一個(gè)子類。如果要新增一個(gè)快餐品類(炒河粉)的話,就需要定義更多的子,會(huì)出現(xiàn)類爆炸的問題。
繼承適合于縱向擴(kuò)展
二、裝飾模式
2.1 裝飾(Decorator)模式中的角色
- 抽象構(gòu)件(Component)角色 :定義一個(gè)抽象接口以規(guī)范準(zhǔn)備接收附加責(zé)任的對象。
- 具體構(gòu)件(Concrete Component)角色 :實(shí)現(xiàn)抽象構(gòu)件,通過裝飾角色為其添加一些職責(zé)。
- 抽象裝飾(Decorator)角色 : 繼承或?qū)崿F(xiàn)抽象構(gòu)件,并包含具體構(gòu)件的實(shí)例,可以通過其子類擴(kuò)展具體構(gòu)件的功能。
- 具體裝飾(ConcreteDecorator)角色 :實(shí)現(xiàn)抽象裝飾的相關(guān)方法,并給具體構(gòu)件對象添加附加的責(zé)任。
2.2 裝飾模式改進(jìn)設(shè)計(jì)UML

2.3 裝飾模式代碼實(shí)現(xiàn)
(1)構(gòu)件代碼
//快餐接口--抽象類或接口實(shí)現(xiàn)都可以
public abstract class FastFood {
private float price;
private String desc;
public FastFood() {
}
public FastFood(float price, String desc) {
this.price = price;
this.desc = desc;
}
public void setPrice(float price) {
this.price = price;
}
public float getPrice() {
return price;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public abstract float cost(); //獲取價(jià)格
}
//炒飯
public class FriedRice extends FastFood {
public FriedRice() {
super(10, "炒飯");
}
public float cost() {
return getPrice();
}
}
//炒面
public class FriedNoodles extends FastFood {
public FriedNoodles() {
super(12, "炒面");
}
public float cost() {
return getPrice();
}
}
(2)抽象裝飾代碼
package com.fupinng3.gar;
/**
* 抽象裝飾
* 即繼承自FastFood,又聚合FastFood
*/
public abstract class Garnish extends FastFood{
private FastFood fastFood;
public Garnish() {
}
public FastFood getFastFood() {
return fastFood;
}
public void setFastFood(FastFood fastFood) {
this.fastFood = fastFood;
}
public Garnish(FastFood fastFood,float price, String desc) {
super(price, desc);
this.fastFood = fastFood;
}
}
(3)具體裝飾
package com.fupinng3.gar;
public class Egg extends Garnish{
public Egg(FastFood fastFood) {
super(fastFood, 2, "雞蛋");
}
@Override
public float cost() {
return getPrice()+getFastFood().cost();
}
@Override
public String getDesc() {
String str1=super.getDesc();
String str2=getFastFood().getDesc();
return str1+str2;
}
}
package com.fupinng3.gar;
public class Bacon extends Garnish{
public Bacon(FastFood fastFood) {
super(fastFood, 5, "培根");
}
public float cost() {
return getPrice()+getFastFood().cost();
}
@Override
public String getDesc() {
return super.getDesc()+getFastFood().getDesc();
}
}
(4)測試代碼
package com.fupinng3.gar;
public class Test {
public static void main(String[] args) {
//來個(gè)炒面
FastFood fastFood=new FriedNoodles();
System.out.println(fastFood.getDesc()+"\t"+fastFood.cost()+"元");
//加個(gè)雞蛋
fastFood=new Egg(fastFood);
System.out.println(fastFood.getDesc()+"\t"+fastFood.cost()+"元");
//再加個(gè)雞蛋
fastFood=new Egg(fastFood);
System.out.println(fastFood.getDesc()+"\t"+fastFood.cost()+"元");
//再加個(gè)培根
fastFood=new Bacon(fastFood);
System.out.println(fastFood.getDesc()+"\t"+fastFood.cost()+"元");
}
}
(5)輸出
炒面 20.0元
雞蛋炒面 22.0元
雞蛋雞蛋炒面 24.0元
培根雞蛋雞蛋炒面 29.0元
一個(gè)現(xiàn)實(shí)生活中的裝飾模式例子:各種顏色、圖案形成的俄羅斯套娃
三、靜態(tài)代理和裝飾者模式的區(qū)別
(1)相同點(diǎn):都是增強(qiáng)目標(biāo)方法
(2)不同點(diǎn):(如下2個(gè)不同點(diǎn)可以理解為1個(gè))
- 目的不同 :裝飾者是為了增強(qiáng)目標(biāo)對象,靜態(tài)代理是為了保護(hù)和隱藏目標(biāo)對象(代理未對外暴露目標(biāo)對象)
- 獲取目標(biāo)對象構(gòu)建的地方不同:裝飾者是由外界傳遞進(jìn)來,可以通過構(gòu)造方法傳遞 靜態(tài)代理是在代理類內(nèi)部創(chuàng)建,以此來隱藏目標(biāo)對象
到此這篇關(guān)于Java設(shè)計(jì)模式之裝飾模式詳解的文章就介紹到這了,更多相關(guān)Java裝飾模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文詳細(xì)講解Java的父子繼承、方法的重寫與super關(guān)鍵字
Java中繼承是通過extends關(guān)鍵字實(shí)現(xiàn),幫助減少代碼重復(fù),提高復(fù)用性,子類繼承父類的屬性和方法,但私有成員除外,方法重寫(override)使子類改造父類方法以適應(yīng)新功能,這篇文章主要介紹了Java的父子繼承、方法的重寫與super關(guān)鍵字的相關(guān)資料,需要的朋友可以參考下2024-10-10
基于JavaBean編輯器讀取peroperties文件的實(shí)例
下面小編就為大家?guī)硪黄贘avaBean編輯器讀取peroperties文件的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10
詳解spring boot使用@Retryable來進(jìn)行重處理
本篇文章主要介紹了詳解spring boot使用@Retryable來進(jìn)行重處理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
SpringBoot與MyBatis-Plus的高效集成方式
本文詳細(xì)介紹了如何在SpringBoot項(xiàng)目中整合MyBatis-Plus,包括環(huán)境準(zhǔn)備、實(shí)體類與Mapper接口定義、CRUD操作、條件構(gòu)造器、事務(wù)管理、安全性考慮、性能優(yōu)化、版本兼容性與遷移、實(shí)際應(yīng)用場景和監(jiān)控與日志等內(nèi)容,通過這些步驟,讀者可以掌握MyBatis-Plus的高級(jí)特性和最佳實(shí)踐2024-11-11
Java調(diào)用計(jì)算機(jī)攝像頭拍照實(shí)現(xiàn)過程解析
這篇文章主要介紹了Java調(diào)用計(jì)算機(jī)攝像頭拍照實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
Java實(shí)現(xiàn)字符串轉(zhuǎn)為駝峰格式的方法詳解
這篇文章主要介紹了如何利用Java語言實(shí)現(xiàn)字符串轉(zhuǎn)為駝峰格式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-07-07

