前言
距離上一次正兒八經地寫隨筆已經有一段時間了,雖然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)。只是發現最近這周自己的思想狀態不是很好,心態上似乎也有點浮躁,所以抽時間來寫點東西,讓自己的心靜一靜。另一方面也想將自己看過的東西實踐并記錄下來,可以方便后續使用時查閱。希望通過這篇隨筆提醒自己,珍惜時間,不忘初心,方得始終。