1. Decorator(装饰)模式
1.1. 概述
l 场景:贵公司编写一个类ReadStrFromFile,专门负责从文件内读取字符串。本来这个功能已经足够了。但是后来发现这些字符串还需要统一变成大写字母。请你编写一个类,能够将字符串转大写字母,并配合上面的类使用,你有何高见?
l 方案1:在主函数内,编写一个类,调用ReadStrFromFile,得到字符串,转大写。
l 方案2:适配器模式,扩展ReadStrFromFile,重写读文件函数
l 评价方案2!
1.2. 解决方法1:使用适配器模式
单向适配器模式是在主模块上接入一个扩展模块,用继承法。代码如下:
class ReadStrFromFile{//主模块 public void read(){ System.out.println("从文件读取字符串"); } }
class Convert{//扩展模块 public void convertToUpper(){ System.out.println("转大写字母"); } }
//适配器模式: class SubReadStrFromFile extends ReadStrFromFile{ private Convert convert; public SubReadStrFromFile(Convert convert){ this.convert = convert; } public void read(){ super.read(); convert.convertToUpper(); } }
public class Decorator1{//客户端,最终使用方 public static void main(String args[]){ SubReadStrFromFile srsff = new SubReadStrFromFile(new Convert()); srsff.read(); } } |
在上面的代码使用适配器模式,使用适配器有优势也有缺点。
优势:能够很好的应付扩展模块的切换
缺陷:扩展模块无法很好的应付主模块的切换
问题类比:Convert为ReadStrFromFile服务,以后又要为ReadStrFromNet服务
用单向适配器模式,就必须为ReadStrFromNet编写子类,很麻烦。
由此我们可以使用装饰模式。
1.3. 解决方法2:使用装饰模式
装饰模式要点:主模块接口注入扩展模块,代码如下:
interface IRead{ public abstract void read(); } class ReadStrFromFile implements IRead{//主模块 public void read(){ System.out.println("从文件读取字符串"); } }
class ReadStrFromNet implements IRead{//主模块 public void read(){ System.out.println("从网络读取字符串"); } }
//装饰模式 class Convert{//扩展模块,可以用Spring装配,可以为任何实现了IRead接口的类服务 private IRead iread; public Convert(IRead iread){ this.iread = iread; } public void convertToUpper(){ iread.read(); System.out.println("转大写字母"); } }
public class Decorator2{//客户端,最终使用方 public static void main(String args[]){
Convert convert = new Convert(new ReadStrFromNet()); convert.convertToUpper(); } } |
1.4. 和适配器的区别
1.5. 装饰模式要点
l 编写一个类,包含一个字符串转大写的函数toUpper。在构造函数内传入原来ReadStr类的引用。在toUpper函数内调用ReadStr的方法,并且做相应操作
l 评价这种方法
l 更好的方法:编写一个接口管理待扩充的类
l 练习:编写一个类,能从文件里面读一行,编译在不改变这个类源代码的基础上,增加另一类,使得它能和这个类配合使用,将文件里面读得的内容倒转
l 案例:大家是否记得Java读中文的方法?
l 用FileReader是不能读中文的,但是这个类有连接到文件的能力,那你是否编写一个类,使用的时候套在FileReader上面?这就是BufferedReader,其实两者的耦合很小。
l 怎么编写?
l FileReader fis = new FileREader(“filename”);
l BufferedReader br = new BufferedReader(fis);