装饰模式java咖啡_浅谈装饰者模式+JAVA I/O中的装饰者模式

本文介绍装饰者模式在饮料店场景的应用,通过实例说明如何避免类爆炸,并展示Java I/O操作中装饰者模式的具体实现。

1. 装饰者模式

举个栗子,假如在一家饮料店中有两种饮料,分别是奶茶和咖啡,相对的有三种调料,蜂蜜、块糖和摩卡,这样消费者就有不同的消费组合,比如加糖摩卡咖啡、蜂蜜摩卡咖啡,加糖奶茶......如果饮料的种类或者调料的种类增多,那么消费组合就会相应的增多,反映到编程代码上就会出现“类爆炸”,而且再添加新的饮料或者调料时会不可避免的改变原有的类的代码,这就违反了设计原则中的开放-关闭原则,即类应该对扩展开放,对修改关闭。

1.1 类图

使用装饰者模式就能很好地解决这个问题,废话不多说,该例子的类图如下:

aadf6dc3c5ef36c0233ae14b70144218.png

其中Beverage是抽象类,CondimentDecorator是继承自Beverage类的抽象类。

1.2 饮料的抽象类

Beverage.java代码:

/**

* @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的代码:

/**

* @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的代码:

/**

* @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的代码:

/**

* @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 调味品 摩卡的实现类

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

}

}

运行结果

ecbaf55fd36ae43942165b0ef90ed8c4.png

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 set=new HashSet();

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 运行结果

f165e93502238af40a95d3ec2d6f3d02.png

程序运行前:

299807ae6809ef84ee5484b959f782c0.png

test.txt中:

fb88aba304172bd9c71dad154a5f0548.png

程序运行后:

72efc64e70497bff05965821b698e26a.png

test.txt中:

08c0e8897e8fe1dd20ce2ecb2e5dc2e8.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值