新聞中心
這篇文章主要介紹“java中的裝飾模式怎么用”,在日常操作中,相信很多人在java中的裝飾模式怎么用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”java中的裝飾模式怎么用”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
成都創(chuàng)新互聯(lián)公司主營西豐網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶App定制開發(fā),西豐h5重慶小程序開發(fā)搭建,西豐網(wǎng)站營銷推廣歡迎西豐等地區(qū)企業(yè)咨詢
1. 模式的定義
如何實現(xiàn)靈活的獎金計算?假設(shè)獎金的計算體系如下:
每個人當(dāng)月業(yè)務(wù)獎金:當(dāng)月銷售額 * 3%
每個人累計獎金:總的回款額 * 0.1%
團(tuán)隊獎金:團(tuán)隊總銷售額 * 1%
獎金計算面臨的問題:
1. 計算邏輯復(fù)雜
2. 要有靈活性,可以方便地增加或者減少功能
3. 動態(tài)組合計算,不同的人參與的計算不同
抽象出來的問題:如何才能透明地給一個對象增加功能,并實現(xiàn)功能的動態(tài)組合?
裝飾模式的定義:
動態(tài)地給一個對象添加一些額外的職責(zé),就增加功能來說,裝飾模式比生成子類更為靈活。
2. UML圖
Component:組件對象的接口,可以給這些對象動態(tài)地添加職責(zé)
ConcreteComponent:具體的組件對象,實現(xiàn)組件接口,通常是被裝飾器裝飾的原始對象,也就是可以給這個對象添加職責(zé)
Decorator:所有裝飾器的抽象父類,需要定義一個與組件接口一致的接口,并持有一個Component對象,其實就是持有一個被裝飾的對象
ConcreteDecorator:具體的裝飾器對象,實現(xiàn)具體要向被裝飾對象添加的功能
代碼:
/**
* 在內(nèi)存中模擬數(shù)據(jù)庫,準(zhǔn)備點測試數(shù)據(jù),好計算獎金
*/public class TempDB {
private TempDB(){} /**
* 記錄每個人的月度銷售額,只用了人員,月份沒有用
*/
public static Map
mapMonthSaleMoney = new HashMap (); static{ //填充測試數(shù)據(jù) mapMonthSaleMoney.put("張三",10000.0);
mapMonthSaleMoney.put("李四",20000.0);
mapMonthSaleMoney.put("王五",30000.0);
}
}/**
* 計算獎金的組件接口
*/public abstract class Component {
/**
* 計算某人在某段時間內(nèi)的獎金,有些參數(shù)在演示中并不會使用,
* 但是在實際業(yè)務(wù)實現(xiàn)上是會用的,為了表示這是個具體的業(yè)務(wù)方法,
* 因此這些參數(shù)被保留了
* @param user 被計算獎金的人員
* @param begin 計算獎金的開始時間
* @param end 計算獎金的結(jié)束時間
* @return 某人在某段時間內(nèi)的獎金
*/
public abstract double calcPrize(String user,Date begin,Date end);
}/**
* 基本的實現(xiàn)計算獎金的類,也是被裝飾器裝飾的對象
*/public class ConcreteComponent extends Component{
public double calcPrize(String user, Date begin, Date end) { //只是一個默認(rèn)的實現(xiàn),默認(rèn)沒有獎金
return 0;
}
}/**
* 裝飾器的接口,需要跟被裝飾的對象實現(xiàn)同樣的接口
*/public abstract class Decorator extends Component{
/**
* 持有被裝飾的組件對象
*/
protected Component c; /**
* 通過構(gòu)造方法傳入被裝飾的對象
* @param c被裝飾的對象
*/
public Decorator(Component c){ this.c = c;
} public double calcPrize(String user, Date begin, Date end) { //轉(zhuǎn)調(diào)組件對象的方法
return c.calcPrize(user, begin, end);
}
}/**
* 裝飾器對象,計算當(dāng)月業(yè)務(wù)獎金
*/public class MonthPrizeDecorator extends Decorator{
public MonthPrizeDecorator(Component c){ super(c);
} public double calcPrize(String user, Date begin, Date end) { //1:先獲取前面運(yùn)算出來的獎金
double money = super.calcPrize(user, begin, end); //2:然后計算當(dāng)月業(yè)務(wù)獎金,按照人員和時間去獲取當(dāng)月的業(yè)務(wù)額,然后再乘以3%
double prize = TempDB.mapMonthSaleMoney.get(user) * 0.03;
System.out.println(user+"當(dāng)月業(yè)務(wù)獎金"+prize); return money + prize;
}
}/**
* 裝飾器對象,計算累計獎金
*/public class SumPrizeDecorator extends Decorator{
public SumPrizeDecorator(Component c){ super(c);
} public double calcPrize(String user, Date begin, Date end) { //1:先獲取前面運(yùn)算出來的獎金
double money = super.calcPrize(user, begin, end); //2:然后計算累計獎金,其實這里應(yīng)該按照人員去獲取累計的業(yè)務(wù)額,然后再乘以0.1%
//簡單演示一下,假定大家的累計業(yè)務(wù)額都是1000000元
double prize = 1000000 * 0.001;
System.out.println(user+"累計獎金"+prize); return money + prize;
}
}/**
* 裝飾器對象,計算當(dāng)月團(tuán)隊業(yè)務(wù)獎金
*/public class GroupPrizeDecorator extends Decorator{
public GroupPrizeDecorator(Component c){ super(c);
} public double calcPrize(String user, Date begin, Date end) { //1:先獲取前面運(yùn)算出來的獎金
double money = super.calcPrize(user, begin, end); //2:然后計算當(dāng)月團(tuán)隊業(yè)務(wù)獎金,先計算出團(tuán)隊總的業(yè)務(wù)額,然后再乘以1%
//假設(shè)都是一個團(tuán)隊的
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)隊業(yè)務(wù)獎金"+prize); return money + prize;
}
}/**
* 使用裝飾模式的客戶端
*/public class Client {
public static void main(String[] args) { //先創(chuàng)建計算基本獎金的類,這也是被裝飾的對象
Component c1 = new ConcreteComponent(); //然后對計算的基本獎金進(jìn)行裝飾,這里要組合各個裝飾
//說明,各個裝飾者之間最好是不要有先后順序的限制,也就是先裝飾誰和后裝飾誰都應(yīng)該是一樣的
//一層一層疊加的功能
//先組合普通業(yè)務(wù)人員的獎金計算
Decorator d1 = new MonthPrizeDecorator(c1);
Decorator d2 = new SumPrizeDecorator(d1);
//注意:這里只需要使用最后組合好的對象調(diào)用業(yè)務(wù)方法即可,會依次調(diào)用回去
//日期對象都沒有用上,所以傳null就可以了
double zs = d2.calcPrize("張三",null,null);
System.out.println("==========張三應(yīng)得獎金:"+zs); double ls = d2.calcPrize("李四",null,null);
System.out.println("==========李四應(yīng)得獎金:"+ls); //如果是業(yè)務(wù)經(jīng)理,還需要一個計算團(tuán)隊的獎金計算
Decorator d3 = new GroupPrizeDecorator(d2); double ww = d3.calcPrize("王五",null,null);
System.out.println("==========王經(jīng)理應(yīng)得獎金:"+ww);
}
}
3. 研磨設(shè)計模式
1)裝飾模式的功能:實現(xiàn)動態(tài)地為對象添加功能,一層一層的包裝
2)類功能的擴(kuò)展:1. 繼承 2.對象的組合
3)Java中的裝飾模式:IO流
InputStream相當(dāng)于Component
FileInputStream,ObjectInputStream,StringBufferInputStream相當(dāng)于ConcreteComponent
FilterInputStream相當(dāng)于Decorator
DataInputStream,BufferedInputStream相當(dāng)于ConcreteDecorator
4)裝飾器模式與AOP
AOP為開發(fā)者提供了一種描述橫切關(guān)注點的機(jī)制,并能夠自動將橫切關(guān)注點植入到面向?qū)ο蟮能浖到y(tǒng)中,從而實現(xiàn)了橫切關(guān)注點的模塊化。
AOP能夠?qū)⒛切┡c業(yè)務(wù)無關(guān),卻被業(yè)務(wù)模塊所共同調(diào)用的邏輯,比如,事務(wù)處理,日志管理,權(quán)限控制,封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,利于未來的維護(hù)和操作。
AOP一個更重要的變化是思想上的變化(主從換位),讓原本主動調(diào)用的功能模塊變成了被動等待。
/**
* 商品銷售管理的業(yè)務(wù)接口 相當(dāng)于Component
*/public interface GoodsSaleEbi {
/**
* 保存銷售信息,本來銷售數(shù)據(jù)應(yīng)該是多條,太麻煩了,為了演示,簡單點
* @param user 操作人員
* @param customer 客戶
* @param saleModel 銷售數(shù)據(jù)
* @return 是否保存成功
*/
public boolean sale(String user,String customer,SaleModel saleModel);
}/**
* 封裝銷售單的數(shù)據(jù),簡單的示意一些
*/public class SaleModel {
/**
* 銷售的商品
*/
private String goods; /**
* 銷售的數(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 "商品名稱="+goods+",購買數(shù)量="+saleNum;
}
}/**
* 業(yè)務(wù)對象
*/public class GoodsSaleEbo implements GoodsSaleEbi{
public boolean sale(String user,String customer, SaleModel saleModel) {
System.out.println(user+"保存了"+customer+"購買 "+saleModel+" 的銷售數(shù)據(jù)"); return true;
}
}/**
* 裝飾器的接口,需要跟被裝飾的對象實現(xiàn)同樣的接口
*/public abstract class Decorator implements GoodsSaleEbi{
/**
* 持有被裝飾的組件對象
*/
protected GoodsSaleEbi ebi; /**
* 通過構(gòu)造方法傳入被裝飾的對象
* @param ebi被裝飾的對象
*/
public Decorator(GoodsSaleEbi ebi){ this.ebi = ebi;
}
}/**
* 實現(xiàn)權(quán)限控制
*/public class CheckDecorator extends Decorator{
public CheckDecorator(GoodsSaleEbi ebi){ super(ebi);
} public boolean sale(String user,String customer, SaleModel saleModel) { //簡單點,只讓張三執(zhí)行這個功能
if(!"張三".equals(user)){
System.out.println("對不起"+user+",你沒有保存銷售單的權(quán)限"); //就不再調(diào)用被裝飾對象的功能了
return false;
}else{ return this.ebi.sale(user, customer, saleModel);
}
}
}/**
* 實現(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ù)功能過后,記錄日志
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
System.out.println("日志記錄:"+user+"于"+df.format(new Date())+"時保存了一條銷售記錄,客戶是"+customer+",購買記錄是"+saleModel); return f;
}
}public class Client {
public static void main(String[] args) { //得到業(yè)務(wù)接口,組合裝飾器
GoodsSaleEbi ebi = new CheckDecorator(new LogDecorator(new GoodsSaleEbo())); //準(zhǔn)備測試數(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ì):動態(tài)組合
到此,關(guān)于“java中的裝飾模式怎么用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
當(dāng)前題目:java中的裝飾模式怎么用
當(dāng)前地址:http://fisionsoft.com.cn/article/gdioid.html