做者:小傅哥
博客:https://bugstack.cnhtml
沉澱、分享、成長,讓本身和他人都能有所收穫!😄
對於代碼你有編程感受嗎
java
不少人寫代碼每每是沒有編程感受的,也就是除了能夠把功能按照固定的流程編寫出流水式的代碼外,很難去思考整套功能服務的擴展性和可維護性。尤爲是在一些較大型的功能搭建上,比較缺失一些駕馭能力,從而致使最終的代碼相對來講不能作到盡善盡美。web
江洋大盜與江洋大偷
spring
兩個本想描述同樣的意思的詞,只因一字只差就讓人以爲一個是好牛,一個好搞笑。每每咱們去開發編程寫代碼時也常常將一些不恰當的用法用於業務需求實現中,當卻不能意識到。一方面是因爲編碼很少缺乏較大型項目的實踐,另外一方面是不思進取的總在以完成需求爲目標缺乏精益求精的工匠精神。編程
書歷來不是看的而是用的
設計模式
在這個學習資料幾乎爆炸的時代,甚至你能夠輕易就獲取幾個T的視頻,小手輕輕一點就收藏一堆文章,但卻不多去看。學習的過程從不僅是簡單的看一遍就能夠,對於一些實操性的技術書籍,若是真的但願學習到知識,那麼必定是把這本書用起來而絕對不是看起來。安全
bugstack蟲洞棧
,回覆源碼下載
獲取(打開獲取的連接,找到序號18)工程 | 描述 |
---|---|
itstack-demo-design-9-00 | 場景模擬工程;模擬單點登陸類 |
itstack-demo-design-9-01 | 使用一坨代碼實現業務需求 |
itstack-demo-design-9-02 | 經過設計模式優化改造代碼,產生對比性從而學習 |
初看上圖感受裝飾器模式有點像俄羅斯套娃、某衆汽車🚕,而裝飾器的核心就是再不改原有類的基礎上給類新增功能。不改變原有類,可能有的小夥伴會想到繼承、AOP切面,固然這些方式均可以實現,可是使用裝飾器模式會是另一種思路更爲靈活,能夠避免繼承致使的子類過多,也能夠避免AOP帶來的複雜性。微信
你熟悉的場景不少用到裝飾器模式cookie
new BufferedReader(new FileReader(""));
,這段代碼你是否熟悉,相信學習java開發到字節流、字符流、文件流的內容時都見到了這樣的代碼,一層嵌套一層,一層嵌套一層,字節流轉字符流等等,而這樣方式的使用就是裝飾器模式的一種體現。併發
在本案例中咱們模擬一個單點登陸功能擴充的場景
通常在業務開發的初期,每每內部的ERP使用只須要判斷帳戶驗證便可,驗證經過後便可訪問ERP的全部資源。但隨着業務的不斷髮展,團隊裏開始出現專門的運營人員、營銷人員、數據人員,每一個人員對於ERP的使用需求不一樣,有些須要建立活動,有些只是查看數據。同時爲了保證數據的安全性,不會讓每一個用戶都有最高的權限。
那麼以往使用的SSO
是一個組件化通用的服務,不能在裏面添加須要的用戶訪問驗證功能。這個時候咱們就可使用裝飾器模式,擴充原有的單點登陸服務。但同時也保證原有功能不受破壞,能夠繼續使用。
itstack-demo-design-9-00 └── src └── main └── java └── org.itstack.demo.design ├── HandlerInterceptor.java └── SsoInterceptor.java
HandlerInterceptor
,實現起接口功能SsoInterceptor
模擬的單點登陸攔截服務。public interface HandlerInterceptor { boolean preHandle(String request, String response, Object handler); }
org.springframework.web.servlet.HandlerInterceptor
實現。public class SsoInterceptor implements HandlerInterceptor{ public boolean preHandle(String request, String response, Object handler) { // 模擬獲取cookie String ticket = request.substring(1, 8); // 模擬校驗 return ticket.equals("success"); } }
HttpServletRequest request
對象中獲取cookie
信息,解析ticket
值作校驗。success
就認爲是容許登陸。此場景大多數實現的方式都會採用繼承類
繼承類的實現方式也是一個比較通用的方式,經過繼承後重寫方法,併發將本身的邏輯覆蓋進去。若是是一些簡單的場景且不須要不斷維護和擴展的,此類實現並不會有什麼,也不會致使子類過多。
itstack-demo-design-9-01 └── src └── main └── java └── org.itstack.demo.design └── LoginSsoDecorator.java
LoginSsoDecorator
繼承 SsoInterceptor
,重寫方法功能。public class LoginSsoDecorator extends SsoInterceptor { private static Map<String, String> authMap = new ConcurrentHashMap<String, String>(); static { authMap.put("huahua", "queryUserInfo"); authMap.put("doudou", "queryUserInfo"); } @Override public boolean preHandle(String request, String response, Object handler) { // 模擬獲取cookie String ticket = request.substring(1, 8); // 模擬校驗 boolean success = ticket.equals("success"); if (!success) return false; String userId = request.substring(9); String method = authMap.get(userId); // 模擬方法校驗 return "queryUserInfo".equals(method); } }
@Test public void test_LoginSsoDecorator() { LoginSsoDecorator ssoDecorator = new LoginSsoDecorator(); String request = "1successhuahua"; boolean success = ssoDecorator.preHandle(request, "ewcdqwt40liuiu", "t"); System.out.println("登陸校驗:" + request + (success ? " 放行" : " 攔截")); }
登陸校驗:1successhuahua 攔截 Process finished with exit code 0
接下來使用裝飾器模式來進行代碼優化,也算是一次很小的重構。
裝飾器主要解決的是直接繼承下因功能的不斷橫向擴展致使子類膨脹的問題,而是用裝飾器模式後就會比直接繼承顯得更加靈活同時這樣也就再也不須要考慮子類的維護。
在裝飾器模式中有四個比較重要點抽象出來的點;
定義抽象接口
實現抽象接口,能夠是一組
定義抽象類並繼承接口中的方法,保證一致性
擴展裝飾具體的實現邏輯
經過以上這四項來實現裝飾器模式,主要核心內容會體如今抽象類的定義和實現上。
itstack-demo-design-9-02 └── src └── main └── java └── org.itstack.demo.design ├── LoginSsoDecorator.java └── SsoDecorator.java
裝飾器模式模型結構
SsoDecorator
,這個類是一個抽象類主要完成了對接口HandlerInterceptor
繼承。public abstract class SsoDecorator implements HandlerInterceptor { private HandlerInterceptor handlerInterceptor; private SsoDecorator(){} public SsoDecorator(HandlerInterceptor handlerInterceptor) { this.handlerInterceptor = handlerInterceptor; } public boolean preHandle(String request, String response, Object handler) { return handlerInterceptor.preHandle(request, response, handler); } }
preHandle
。public class LoginSsoDecorator extends SsoDecorator { private Logger logger = LoggerFactory.getLogger(LoginSsoDecorator.class); private static Map<String, String> authMap = new ConcurrentHashMap<String, String>(); static { authMap.put("huahua", "queryUserInfo"); authMap.put("doudou", "queryUserInfo"); } public LoginSsoDecorator(HandlerInterceptor handlerInterceptor) { super(handlerInterceptor); } @Override public boolean preHandle(String request, String response, Object handler) { boolean success = super.preHandle(request, response, handler); if (!success) return false; String userId = request.substring(8); String method = authMap.get(userId); logger.info("模擬單點登陸方法訪問攔截校驗:{} {}", userId, method); // 模擬方法校驗 return "queryUserInfo".equals(method); } }
SsoDecorator
,那麼如今就能夠擴展方法;preHandle
preHandle
的實現中能夠看到,這裏只關心擴展部分的功能,同時不會影響原有類的核心服務,也不會由於使用繼承方式而致使的多餘子類,增長了總體的靈活性。@Test public void test_LoginSsoDecorator() { LoginSsoDecorator ssoDecorator = new LoginSsoDecorator(new SsoInterceptor()); String request = "1successhuahua"; boolean success = ssoDecorator.preHandle(request, "ewcdqwt40liuiu", "t"); System.out.println("登陸校驗:" + request + (success ? " 放行" : " 攔截")); }
new SsoInterceptor()
,傳遞給裝飾器,讓裝飾器能夠執行擴充的功能。23:50:50.796 [main] INFO o.i.demo.design.LoginSsoDecorator - 模擬單點登陸方法訪問攔截校驗:huahua queryUserInfo 登陸校驗:1successhuahua 放行 Process finished with exit code 0
list
集合消息,但你又不但願全部的代碼類都去修改這部分邏輯。那麼可使用裝飾器模式進行適配list
集合,給使用者依然是for
循環後的單個消息。