前言
距离上一次正儿八经地写随笔已经有一段时间了,虽然2月10号有一篇关于泛型的小记,但是其实只是简单地将自己的学习代码贴上来,为了方便后续使用时查阅,并没有多少文字和理解感悟。之所以在今天觉得有必要写点东西,主要是因为对自己这一周的状态不满意。表面上看,周一到周三都是加班到比较晚,周一回到家快10点了,还看了会书到12点半,但是实际上,我知道,自己的精神状态出现了松懈,心态上有点浮躁,态度的问题是不能容忍的。因此决定在今天写点东西,希望让自己能静下来,重新出发。
一、OOP(Object Oriented Programming)中的装饰器模式
在《HeadFirst设计模式》中,作者给出的定义是:装饰者模式动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
其实从字面上,这个定义并不是那么容易理解。我自己总结了下OOP中的装饰器模式特点:
1. 装饰者与被装饰者会继承相同的父类。
2. 装饰者会有一个私有变量持有被装饰者的引用。
3. 装饰者将自己的属性附加到到被装饰者上。
为了学以致用,我想用生活中的例子来描述装饰者模式的使用姿势。
场景:最近我厂由于业务扩展,有大批职位需要招聘,而各个职位对求职者的要求参差不齐,其中有一部分岗位对人才的要求非常相近但是又不完全相同,这边提取出一些出现频率比较高的要求:计算机专业,熟悉Java,熟悉JVM,测试分析能力,自动化测试能力。
下面就是使用装饰者模式实现的代码:
Job(被装饰者)基类:
public abstract class Job {private String title="unknown";public String getTitle(){return title;};public void setTitle(String title){this.title = title;}public abstract String getJobDescription(); }
JobRequirement(装饰者)基类:
public abstract class JobRequirement extends Job { //重写getDescription方法public abstract String getJobDescription(); }
SoftwareDeveloper(职位1):
public class SoftwareDeveloper extends Job{public SoftwareDeveloper(){this.setTitle("Software Developer");}@Overridepublic String getJobDescription() {return "familiar with Java";} }
SoftwareTester(职位2)
public class SoftwareTester extends Job{public SoftwareTester() {this.setTitle("Software Tester");}@Overridepublic String getJobDescription() {return "familiar with test-analysis";} }
AutotestRequirement(自动化测试要求):
public class AutotestRequirement extends JobRequirement{Job job;public AutotestRequirement(Job job){this.job=job;}@Overridepublic String getTitle() {return job.getTitle();}@Overridepublic String getJobDescription() {return job.getJobDescription() + "; " + "familiar with autotest";} }
JVMRequiremement(JVM要求):
public class JVMRequirement extends JobRequirement {Job job;public JVMRequirement(Job job) {this.job = job;}@Overridepublic String getTitle() {return job.getTitle();}@Overridepublic String getJobDescription() {return job.getJobDescription() + "; " + "familiar with JVM";} }
MajorRequirement(专业要求):
public class MajorRequirement extends JobRequirement {Job job;public MajorRequirement(Job job) {this.job = job;}@Overridepublic String getTitle() {return job.getTitle();}@Overridepublic String getJobDescription() {return job.getJobDescription() + "; " + "major in Computer Science";} }
执行Main类:
1 public class Main { 2 public static void main(String[] args) { 3 //develop 4 Job developer = new SoftwareDeveloper(); 5 developer = new MajorRequirement(developer); 6 developer = new JVMRequirement(developer); 7 System.out.println("Title: " + developer.getTitle()); 8 System.out.println("JD: " + developer.getJobDescription()); 9 //tester 10 Job tester = new SoftwareTester(); 11 tester = new AutotestRequirement(new MajorRequirement(tester)); 12 System.out.println("Title: " + tester.getTitle()); 13 System.out.println("JD: " + tester.getJobDescription()); 14 } 15 }
执行结果:
Title: Software Developer
JD: familiar with Java; major in Computer Science; familiar with JVM
Title: Software Tester
JD: familiar with test-analysis; major in Computer Science; familiar with autotest
可以看到,使用装饰者的代码非常简洁,SoftwareDeveloper本是一个普通的开发岗位,你可以通过加不同的装饰器给这个岗位增加特殊的要求。当有新的职位要求要加入时,只要创建新的requirement类来装饰即可。
二、Python中的装饰器
上一节介绍了OOP中的装饰器设计模式的思想和用法,下面简单谈谈Python中的装饰器。关于Python中的装饰器使用,这里不细讲,有兴趣可以直接查询廖雪峰的Python教程:《装饰器-廖雪峰的官方网站》。这里主要谈谈两者的区别:
1. Python中的装饰器实际上是基于函数的装饰,而面向对象的装饰器思想是基于类的装饰。
Python中的装饰器,实际上是通过语法实现基于函数的装饰,增强原有函数的功能。它通过将一些公有操作(比如:日志打印,校验网站session中是否已存在登录信息等)抽取出来,在各个需要这些公有操作的函数上方通过增加“@装饰器名”的方式来增强函数的功能。缺点是:当一个方法加上装饰器后,不能再调用原来的方法。
面向对象中的装饰器,是基于类的装饰。装饰者与被装饰者继承相同的父类,准确地应该说是有相同的“祖先”。它通过一系列的封装,使得更多的类的方法可以被复用。缺点:可能会有大量的类,造成API调用时的困扰。
2. 装饰器模式是一种设计思想,Python也是一种面向对象的语言,当然也可以使用面向对象的方式来实现装饰器模式。
三、Java I/O中的装饰者模式应用
上图是简单的InputStream类图(有些类没有完全列出),可以看到InputSream是一个父类,下面有4个子类,其中FileInputStream、StringBufferInputStream、ByteArrayInputStream都是被装饰者,是可以被装饰者包装起来的具体组件;FilterInputSream是一个抽象装饰者,下面有4个具体的装饰者类:PushbackInputStream、BufferedInputStream、DataInputStream、LineNumberInputStream。
这样一看,Java I/O的结构关系似乎就明了了许多,但是其中具体的细节,还是必须要抽时间系统地学习一番。
四、写在最后
其实对我来说,第一季度已经过去了70%,后续还有非常繁忙地迭代测试任务,没有多少时间可以用来完成自己第一季度的计划。在这个时间点,我更应该做的是去学习自己计划中的任务(YARN)。只是发现最近这周自己的思想状态不是很好,心态上似乎也有点浮躁,所以抽时间来写点东西,让自己的心静一静。另一方面也想将自己看过的东西实践并记录下来,可以方便后续使用时查阅。希望通过这篇随笔提醒自己,珍惜时间,不忘初心,方得始终。