溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

java中的裝飾模式怎么用

發(fā)布時(shí)間:2021-07-24 10:50:04 來(lái)源:億速云 閱讀:120 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要介紹“java中的裝飾模式怎么用”,在日常操作中,相信很多人在java中的裝飾模式怎么用問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”java中的裝飾模式怎么用”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

1. 模式的定義

如何實(shí)現(xiàn)靈活的獎(jiǎng)金計(jì)算?假設(shè)獎(jiǎng)金的計(jì)算體系如下:

  • 每個(gè)人當(dāng)月業(yè)務(wù)獎(jiǎng)金:當(dāng)月銷(xiāo)售額 * 3%

  • 每個(gè)人累計(jì)獎(jiǎng)金:總的回款額 * 0.1%

  • 團(tuán)隊(duì)獎(jiǎng)金:團(tuán)隊(duì)總銷(xiāo)售額 * 1%

獎(jiǎng)金計(jì)算面臨的問(wèn)題: 
1. 計(jì)算邏輯復(fù)雜 
2. 要有靈活性,可以方便地增加或者減少功能 
3. 動(dòng)態(tài)組合計(jì)算,不同的人參與的計(jì)算不同

抽象出來(lái)的問(wèn)題:如何才能透明地給一個(gè)對(duì)象增加功能,并實(shí)現(xiàn)功能的動(dòng)態(tài)組合?

裝飾模式的定義: 
動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé),就增加功能來(lái)說(shuō),裝飾模式比生成子類(lèi)更為靈活。

2. UML圖

java中的裝飾模式怎么用 
Component:組件對(duì)象的接口,可以給這些對(duì)象動(dòng)態(tài)地添加職責(zé)

ConcreteComponent:具體的組件對(duì)象,實(shí)現(xiàn)組件接口,通常是被裝飾器裝飾的原始對(duì)象,也就是可以給這個(gè)對(duì)象添加職責(zé)

Decorator:所有裝飾器的抽象父類(lèi),需要定義一個(gè)與組件接口一致的接口,并持有一個(gè)Component對(duì)象,其實(shí)就是持有一個(gè)被裝飾的對(duì)象

ConcreteDecorator:具體的裝飾器對(duì)象,實(shí)現(xiàn)具體要向被裝飾對(duì)象添加的功能

代碼:

/**

 * 在內(nèi)存中模擬數(shù)據(jù)庫(kù),準(zhǔn)備點(diǎn)測(cè)試數(shù)據(jù),好計(jì)算獎(jiǎng)金

 */public class TempDB {

    private TempDB(){}    /**

     * 記錄每個(gè)人的月度銷(xiāo)售額,只用了人員,月份沒(méi)有用

     */

    public static Map<String,Double> mapMonthSaleMoney = new HashMap<String,Double>();    static{        //填充測(cè)試數(shù)據(jù)

        mapMonthSaleMoney.put("張三",10000.0);

        mapMonthSaleMoney.put("李四",20000.0);

        mapMonthSaleMoney.put("王五",30000.0);

    }

}/**

 * 計(jì)算獎(jiǎng)金的組件接口

 */public abstract class Component {

    /**

     * 計(jì)算某人在某段時(shí)間內(nèi)的獎(jiǎng)金,有些參數(shù)在演示中并不會(huì)使用,

     * 但是在實(shí)際業(yè)務(wù)實(shí)現(xiàn)上是會(huì)用的,為了表示這是個(gè)具體的業(yè)務(wù)方法,

     * 因此這些參數(shù)被保留了

     * @param user 被計(jì)算獎(jiǎng)金的人員

     * @param begin 計(jì)算獎(jiǎng)金的開(kāi)始時(shí)間

     * @param end 計(jì)算獎(jiǎng)金的結(jié)束時(shí)間

     * @return 某人在某段時(shí)間內(nèi)的獎(jiǎng)金

     */

    public abstract double calcPrize(String user,Date begin,Date end);

}/**

 * 基本的實(shí)現(xiàn)計(jì)算獎(jiǎng)金的類(lèi),也是被裝飾器裝飾的對(duì)象

 */public class ConcreteComponent extends Component{


    public double calcPrize(String user, Date begin, Date end) {        //只是一個(gè)默認(rèn)的實(shí)現(xiàn),默認(rèn)沒(méi)有獎(jiǎng)金

        return 0;

    }

}/**

 * 裝飾器的接口,需要跟被裝飾的對(duì)象實(shí)現(xiàn)同樣的接口

 */public abstract class Decorator extends Component{

    /**

     * 持有被裝飾的組件對(duì)象

     */

    protected Component c;    /**

     * 通過(guò)構(gòu)造方法傳入被裝飾的對(duì)象

     * @param c被裝飾的對(duì)象

     */

    public Decorator(Component c){        this.c = c;

    }    public double calcPrize(String user, Date begin, Date end) {        //轉(zhuǎn)調(diào)組件對(duì)象的方法

        return c.calcPrize(user, begin, end);

    }

}/**

 * 裝飾器對(duì)象,計(jì)算當(dāng)月業(yè)務(wù)獎(jiǎng)金

 */public class MonthPrizeDecorator extends Decorator{

    public MonthPrizeDecorator(Component c){        super(c);

    }    public double calcPrize(String user, Date begin, Date end) {        //1:先獲取前面運(yùn)算出來(lái)的獎(jiǎng)金

        double money = super.calcPrize(user, begin, end);        //2:然后計(jì)算當(dāng)月業(yè)務(wù)獎(jiǎng)金,按照人員和時(shí)間去獲取當(dāng)月的業(yè)務(wù)額,然后再乘以3%

        double prize = TempDB.mapMonthSaleMoney.get(user) * 0.03;

        System.out.println(user+"當(dāng)月業(yè)務(wù)獎(jiǎng)金"+prize);        return money + prize;

    }


}/**

 * 裝飾器對(duì)象,計(jì)算累計(jì)獎(jiǎng)金

 */public class SumPrizeDecorator extends Decorator{

    public SumPrizeDecorator(Component c){        super(c);

    }    public double calcPrize(String user, Date begin, Date end) {        //1:先獲取前面運(yùn)算出來(lái)的獎(jiǎng)金

        double money = super.calcPrize(user, begin, end);        //2:然后計(jì)算累計(jì)獎(jiǎng)金,其實(shí)這里應(yīng)該按照人員去獲取累計(jì)的業(yè)務(wù)額,然后再乘以0.1%

        //簡(jiǎn)單演示一下,假定大家的累計(jì)業(yè)務(wù)額都是1000000元

        double prize = 1000000 * 0.001;

        System.out.println(user+"累計(jì)獎(jiǎng)金"+prize);        return money + prize;

    }


}/**

 * 裝飾器對(duì)象,計(jì)算當(dāng)月團(tuán)隊(duì)業(yè)務(wù)獎(jiǎng)金

 */public class GroupPrizeDecorator extends Decorator{

    public GroupPrizeDecorator(Component c){        super(c);

    }    public double calcPrize(String user, Date begin, Date end) {        //1:先獲取前面運(yùn)算出來(lái)的獎(jiǎng)金

        double money = super.calcPrize(user, begin, end);        //2:然后計(jì)算當(dāng)月團(tuán)隊(duì)業(yè)務(wù)獎(jiǎng)金,先計(jì)算出團(tuán)隊(duì)總的業(yè)務(wù)額,然后再乘以1%

        //假設(shè)都是一個(gè)團(tuán)隊(duì)的

        double group = 0.0;        for(double d : TempDB.mapMonthSaleMoney.values()){

            group += d;

        }        double prize = group * 0.01;

        System.out.println(user+"當(dāng)月團(tuán)隊(duì)業(yè)務(wù)獎(jiǎng)金"+prize);        return money + prize;

    }


}/**

 * 使用裝飾模式的客戶(hù)端

 */public class Client {

    public static void main(String[] args) {        //先創(chuàng)建計(jì)算基本獎(jiǎng)金的類(lèi),這也是被裝飾的對(duì)象

        Component c1 = new ConcreteComponent();        //然后對(duì)計(jì)算的基本獎(jiǎng)金進(jìn)行裝飾,這里要組合各個(gè)裝飾

        //說(shuō)明,各個(gè)裝飾者之間最好是不要有先后順序的限制,也就是先裝飾誰(shuí)和后裝飾誰(shuí)都應(yīng)該是一樣的



        //一層一層疊加的功能

        //先組合普通業(yè)務(wù)人員的獎(jiǎng)金計(jì)算

        Decorator d1 = new MonthPrizeDecorator(c1);

        Decorator d2 = new SumPrizeDecorator(d1);   


        //注意:這里只需要使用最后組合好的對(duì)象調(diào)用業(yè)務(wù)方法即可,會(huì)依次調(diào)用回去

        //日期對(duì)象都沒(méi)有用上,所以傳null就可以了

        double zs = d2.calcPrize("張三",null,null);       

        System.out.println("==========張三應(yīng)得獎(jiǎng)金:"+zs);        double ls = d2.calcPrize("李四",null,null);

        System.out.println("==========李四應(yīng)得獎(jiǎng)金:"+ls);        //如果是業(yè)務(wù)經(jīng)理,還需要一個(gè)計(jì)算團(tuán)隊(duì)的獎(jiǎng)金計(jì)算

        Decorator d3 = new GroupPrizeDecorator(d2);        double ww = d3.calcPrize("王五",null,null);

        System.out.println("==========王經(jīng)理應(yīng)得獎(jiǎng)金:"+ww);


    }

}

3. 研磨設(shè)計(jì)模式

1)裝飾模式的功能:實(shí)現(xiàn)動(dòng)態(tài)地為對(duì)象添加功能,一層一層的包裝

2)類(lèi)功能的擴(kuò)展:1. 繼承 2.對(duì)象的組合

3)Java中的裝飾模式:IO流 
java中的裝飾模式怎么用

  • InputStream相當(dāng)于Component

  • FileInputStream,ObjectInputStream,StringBufferInputStream相當(dāng)于ConcreteComponent

  • FilterInputStream相當(dāng)于Decorator

  • DataInputStream,BufferedInputStream相當(dāng)于ConcreteDecorator

4)裝飾器模式與AOP 
AOP為開(kāi)發(fā)者提供了一種描述橫切關(guān)注點(diǎn)的機(jī)制,并能夠自動(dòng)將橫切關(guān)注點(diǎn)植入到面向?qū)ο蟮能浖到y(tǒng)中,從而實(shí)現(xiàn)了橫切關(guān)注點(diǎn)的模塊化。 
java中的裝飾模式怎么用 
AOP能夠?qū)⒛切┡c業(yè)務(wù)無(wú)關(guān),卻被業(yè)務(wù)模塊所共同調(diào)用的邏輯,比如,事務(wù)處理,日志管理,權(quán)限控制,封裝起來(lái),便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,利于未來(lái)的維護(hù)和操作。 
AOP一個(gè)更重要的變化是思想上的變化(主從換位),讓原本主動(dòng)調(diào)用的功能模塊變成了被動(dòng)等待。

/**

 * 商品銷(xiāo)售管理的業(yè)務(wù)接口  相當(dāng)于Component

 */public interface GoodsSaleEbi {

    /**

     * 保存銷(xiāo)售信息,本來(lái)銷(xiāo)售數(shù)據(jù)應(yīng)該是多條,太麻煩了,為了演示,簡(jiǎn)單點(diǎn)

     * @param user 操作人員

     * @param customer 客戶(hù)

     * @param saleModel 銷(xiāo)售數(shù)據(jù)

     * @return 是否保存成功

     */

    public boolean sale(String user,String customer,SaleModel saleModel);

}/**

 * 封裝銷(xiāo)售單的數(shù)據(jù),簡(jiǎn)單的示意一些

 */public class SaleModel {

    /**

     * 銷(xiāo)售的商品

     */

    private String goods;    /**

     * 銷(xiāo)售的數(shù)量

     */

    private int saleNum;    public String getGoods() {        return goods;

    }    public void setGoods(String goods) {        this.goods = goods;

    }    public int getSaleNum() {        return saleNum;

    }    public void setSaleNum(int saleNum) {        this.saleNum = saleNum;

    }    public String toString(){        return "商品名稱(chēng)="+goods+",購(gòu)買(mǎi)數(shù)量="+saleNum;

    }

}/**

 * 業(yè)務(wù)對(duì)象

 */public class GoodsSaleEbo implements GoodsSaleEbi{


    public boolean sale(String user,String customer, SaleModel saleModel) {

        System.out.println(user+"保存了"+customer+"購(gòu)買(mǎi) "+saleModel+" 的銷(xiāo)售數(shù)據(jù)");        return true;

    }

}/**

 * 裝飾器的接口,需要跟被裝飾的對(duì)象實(shí)現(xiàn)同樣的接口

 */public abstract class Decorator implements GoodsSaleEbi{

    /**

     * 持有被裝飾的組件對(duì)象

     */

    protected GoodsSaleEbi ebi;    /**

     * 通過(guò)構(gòu)造方法傳入被裝飾的對(duì)象

     * @param ebi被裝飾的對(duì)象

     */

    public Decorator(GoodsSaleEbi ebi){        this.ebi = ebi;

    }

}/**

 * 實(shí)現(xiàn)權(quán)限控制

 */public class CheckDecorator extends Decorator{

    public CheckDecorator(GoodsSaleEbi ebi){        super(ebi);

    }    public boolean sale(String user,String customer, SaleModel saleModel) {        //簡(jiǎn)單點(diǎn),只讓張三執(zhí)行這個(gè)功能

        if(!"張三".equals(user)){

            System.out.println("對(duì)不起"+user+",你沒(méi)有保存銷(xiāo)售單的權(quán)限");            //就不再調(diào)用被裝飾對(duì)象的功能了

            return false;

        }else{            return this.ebi.sale(user, customer, saleModel);

        }       

    }

}/**

 * 實(shí)現(xiàn)日志記錄

 */public class LogDecorator extends Decorator{

    public LogDecorator(GoodsSaleEbi ebi){        super(ebi);

    }    public boolean sale(String user,String customer, SaleModel saleModel) {        //執(zhí)行業(yè)務(wù)功能

        boolean f = this.ebi.sale(user, customer, saleModel);        //在執(zhí)行業(yè)務(wù)功能過(guò)后,記錄日志

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

        System.out.println("日志記錄:"+user+"于"+df.format(new Date())+"時(shí)保存了一條銷(xiāo)售記錄,客戶(hù)是"+customer+",購(gòu)買(mǎi)記錄是"+saleModel);        return f;

    }


}public class Client {

    public static void main(String[] args) {        //得到業(yè)務(wù)接口,組合裝飾器

        GoodsSaleEbi ebi = new CheckDecorator(new LogDecorator(new GoodsSaleEbo()));        //準(zhǔn)備測(cè)試數(shù)據(jù)

        SaleModel saleModel = new SaleModel();

        saleModel.setGoods("Moto手機(jī)");

        saleModel.setSaleNum(2);        //調(diào)用業(yè)務(wù)功能

        ebi.sale("張三","張三豐", saleModel);

        ebi.sale("李四","張三豐", saleModel);

    }

}

5)裝飾器模式的本質(zhì):動(dòng)態(tài)組合

到此,關(guān)于“java中的裝飾模式怎么用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI