淺談裝飾者模式+JAVA I/O中的裝飾者模式

1. 裝飾者模式

舉個栗子,假如在一家飲料店中有兩種飲料,分別是奶茶和咖啡,相對的有三種調料,蜂蜜、塊糖和摩卡,這樣消費者就有不一樣的消費組合,好比加糖摩卡咖啡、蜂蜜摩卡咖啡,加糖奶茶......若是飲料的種類或者調料的種類增多,那麼消費組合就會相應的增多,反映到編程代碼上就會出現「類爆炸」,並且再添加新的飲料或者調料時會不可避免的改變原有的類的代碼,這就違反了設計原則中的開放-關閉原則,即類應該對擴展開放,對修改關閉。java

1.1 類圖

使用裝飾者模式就能很好地解決這個問題,廢話很少說,該例子的類圖以下:編程

其中Beverage是抽象類,CondimentDecorator是繼承自Beverage類的抽象類。緩存

1.2 飲料的抽象類

Beverage.java代碼:ide

/**
 * @author yylin
 */
public abstract class Beverage {

	// 飲料的描述
	protected String description;

	public Beverage() {
		description = "飲料的抽象類";
	}

	public String getDescription() {
		return description;
	}

	public abstract double cost();

}

1.3 調味品的抽象類

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()方法
	
}

1.4 飲料 奶茶的實現類

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;
	}

}

1.5 飲料 咖啡的實現類

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() + "元");
	}

}

運行結果

2. JAVA I/O中的裝飾者模式

例題:

l先從文件test.txt中讀Employee對象的數據存HashMap,

l再把HashMap中的Employee對象的數據存到一個新的文件test2.txt。

代碼:

2.1 Employee實體類Employee.java

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;
	}
}

2.2 測試類TestFileIO.java

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();
		}
	}
}

2.3 運行結果

程序運行前:

test.txt中:

程序運行後:

test.txt中:

相關文章
相關標籤/搜索