舉個栗子,假如在一家飲料店中有兩種飲料,分別是奶茶和咖啡,相對的有三種調料,蜂蜜、塊糖和摩卡,這樣消費者就有不一樣的消費組合,好比加糖摩卡咖啡、蜂蜜摩卡咖啡,加糖奶茶......若是飲料的種類或者調料的種類增多,那麼消費組合就會相應的增多,反映到編程代碼上就會出現「類爆炸」,並且再添加新的飲料或者調料時會不可避免的改變原有的類的代碼,這就違反了設計原則中的開放-關閉原則,即類應該對擴展開放,對修改關閉。java
使用裝飾者模式就能很好地解決這個問題,廢話很少說,該例子的類圖以下:編程
其中Beverage是抽象類,CondimentDecorator是繼承自Beverage類的抽象類。緩存
Beverage.java代碼:ide
/** * @author yylin */ public abstract class Beverage { // 飲料的描述 protected String description; public Beverage() { description = "飲料的抽象類"; } public String getDescription() { return description; } public abstract double cost(); }
CondimentDecorator.java代碼:測試
/** * @author yylin */ // 調味品裝飾者,繼承自飲料的抽象類 public abstract class CondimentDecorator extends Beverage { public CondimentDecorator() { description = "調味品的抽象類"; } @Override public abstract String getDescription();//全部的調料品裝飾者必須重寫getDescription()方法 @Override public abstract double cost();//全部的調料品裝飾者必須重寫cost()方法 }
TeaMilk.java的代碼:this
/** * @author yylin */ public class TeaMilk extends Beverage { public TeaMilk(){ //飲料的描述 description="奶茶"; } /* (non-Javadoc) * @see Beverage#cost() */ @Override public double cost() { //奶茶一杯三塊錢 return 3.0; } }
Coffee.java的代碼:spa
/** * @author yylin */ public class Coffee extends Beverage { public Coffee() { //飲料的描述 description="咖啡"; } /* (non-Javadoc) * @see Beverage#cost() */ @Override public double cost() { //咖啡一杯四塊錢 return 4.0; } }
1.6 調味品 蜂蜜的實現類設計
Honey.java的代碼:3d
/** * @author yylin */ // 蜂蜜,繼承自調味品抽象類 public class Honey extends CondimentDecorator { // 記錄飲料的變量,是被裝飾者 Beverage beverage; // 讓被裝飾者記錄到實例變量中 public Honey(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { // 描述調味品和飲料 return "蜂蜜" + beverage.getDescription(); } /* * (non-Javadoc) * * @see CondimentDecorator#cost() */ @Override public double cost() { // 加蜂蜜一塊錢,計算加了蜂蜜的飲料的價錢 return 1.0 + beverage.cost(); } }
1.7 調味品 摩卡的實現類code
Mocha.java的代碼:
/** * @author yylin */ // 摩卡,繼承自調味品裝飾者 public class Mocha extends CondimentDecorator { // 用一個變量記錄飲料,也就是被裝飾者 Beverage beverage; // 把被裝飾者記錄到實例變量中 public Mocha(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { // 描述調味品和飲料 return "摩卡" + beverage.getDescription(); } @Override public double cost() { // 加摩卡一塊錢,計算加了摩卡的飲料的價錢 return 1.0 + beverage.cost(); } }
1.8 調味品 糖的實現類
Sugar.java的代碼:
/** * * @author yylin * */ // 糖,繼承自調味品抽象類 public class Sugar extends CondimentDecorator { // 用一個變量記錄飲料,也就是被裝飾者 Beverage beverage; // 把被裝飾者記錄到實例變量中 public Sugar(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { // 描述加糖的飲料 return "加糖" + beverage.getDescription(); } @Override public double cost() { // 計算加了糖的飲料的價錢 return 1.0 + beverage.cost(); } }
1.9 測試類
/** * @author yylin * */ //測試類 public class TestMain { public static void main(String[] args) { // 點一杯蜂蜜摩卡咖啡 Beverage beverage1 = new Coffee();// 定義咖啡對象 beverage1 = new Mocha(beverage1);// 用摩卡裝飾 beverage1 = new Honey(beverage1);// 用蜂蜜裝飾 System.out.println("顧客點了(" + beverage1.getDescription() + ")\n價格是:" + beverage1.cost() + "元"); // 點一杯加糖奶茶 Beverage beverage2 = new TeaMilk();// 定義奶茶對象 beverage2 = new Sugar(beverage2);// 用糖裝飾 System.out.println("顧客點了(" + beverage2.getDescription() + ")\n價格是:" + beverage2.cost() + "元"); } }
例題:
l先從文件test.txt中讀Employee對象的數據存到HashMap,
l再把HashMap中的Employee對象的數據存到一個新的文件test2.txt。
代碼:
package com.nwpu; /** * * @author yylin * */ public class Employee { private String id; private String name; private String department; public Employee() { } public Employee(String id, String name, String department) { this.id = id; this.name = name; this.department = department; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } @Override public String toString() { return id+","+name+","+department; } }
package com.nwpu; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.HashSet; import java.util.Set; /** * * @author yylin * 讀取文件時: * 一行一行讀取文件,解決讀取中文字符時出現亂碼。 * 流的關閉順序:先打開的後關,後打開的先關, * 不然有可能出現java.io.IOException: Stream closed異常。 * * 寫入文件時: * 一行一行寫入文件,解決寫入中文字符時出現亂碼。 * 流的關閉順序:先打開的後關,後打開的先關, * 不然有可能出現java.io.IOException: Stream closed異常。 */ public class TestFileIO { public static void main(String[] args) { /** * read file */ FileInputStream fis=null;//文件輸入流 InputStreamReader isr=null;//讀入輸入流 BufferedReader br=null;//對讀入的文件流緩存 Set<Employee> set=new HashSet<Employee>(); try { String fileURL="E:/test/test.txt"; fis=new FileInputStream(fileURL); //解決讀入中文亂碼的問題 + 用InputStreamReader類裝飾FileInputStream類 isr=new InputStreamReader(fis,"UTF-8"); //用BufferedReader類裝飾BufferedReader類 br=new BufferedReader(isr); String line=""; String arrs[]=null; //按行讀入 while ((line=br.readLine())!=null) { System.out.println(line);//輸出讀入的行 arrs=line.split(","); //注入對象 set.add(new Employee(arrs[0],arrs[1],arrs[2])); } //流的關閉順序:先打開的後關,後打開的先關 br.close(); isr.close(); fis.close(); } catch (Exception e) { e.printStackTrace(); } for (Employee e : set) { System.out.println(e.toString()); } /** * write file */ FileOutputStream fos=null;//文件輸出流 OutputStreamWriter osw=null;//寫出輸出流 BufferedWriter bw=null;//緩存寫出的輸出流 try { String fileURL="E:/test/test2.txt"; fos=new FileOutputStream(fileURL); //解決中文亂碼問題 + 用OutputStreamWriter類裝飾FileOutputStream類 osw=new OutputStreamWriter(fos,"UTF-8"); //用BufferedWriter類裝飾OutputStreamWriter類 bw=new BufferedWriter(osw); for (Employee e : set) { bw.write(e.toString()+"\r\n"); } //注意關閉的前後順序,先打開的後關閉,後打開的先關閉 bw.close(); osw.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } }
程序運行前:
test.txt中:
程序運行後:
test.txt中: