標籤:java designpattern 重構 方法類型化
方法類型化——將某個或某些方法(準確的說,是方法頭或介面) 提升為類型,是方法型模式的共同技術基礎和設計思路。
Java中以抽象類別或介面類型封裝該介面。Java介面的作用在此被充分展示。
策略模式中,排序策略int[]sort(int[] arr)被抽象類別IntSort封裝。更多的方法類型化例子在隨後的章節中介紹。本節將介紹方法對象化的兩個重要應用。
1. 避免類型爆炸
假定類Person有eat()方法——大家全部用筷子(final方法);有say()方法——每人說自己的方言。於是,類Person代碼如3-5所示。按照“地區”可以設計Person的各種子類如BeiJin、Wuhan等——假設程式員可以容忍這樣的30個子類。
再假定Person還有walk()方法——慢條斯理、風風火火等七八種實現方式。
請問,你如何面對慢條斯理的武漢人、風風火火的上海人……say()與walk()的任意組合將導致至少30*7即210個以上的Person的子類。這是不可容忍的設計。
常式3-5組合的數目package method.strategy;public abstract class Person{ public final void eat(){ System.out.println("用筷子"); } abstract public void say();//每人說自己的方言abstract public void walk();//慢條斯理、風風火火等七八種實現方式}
為了避免類型(數量)的爆炸,可以將say()和walk()類型化,作為兩個策略類層次各自封裝,取名SayBehavior和WalkBehavior。於是類Person的類層次轉化為方法類型或策略類WalkBehavior、SayBehavior的類層次。重構後,系統中類的數量從m*n降低為m+n+2。
常式 3 6 重構Person類package method.strategy;import tool.God;public class Person{ private WalkBehavior walk = null; private SayBehavior say = null; public Person(){ walk = (WalkBehavior)God.create("3-6-Walk"); say = (SayBehavior)God.create("3-6-Say"); } public final void eat(){ System.out.println("用筷子"); } public void say(){ this.say.say(); } public void walk(){ this.walk.walk(); }}此時,Person是兩個策略類的環境類,它的使用者App僅依賴環境類。
package method.strategy;public class App{ public static void main(String args[]){ Person one = new Person(); //內容物件 one.say(); one.walk(); }}
由這個例子,大家聯想到什麼模式?
2.無限可能性和函數介面
如果Person只有一個需要多態化的方法如say(),通常Person本身作為策略類而非定義一個SayBehavior。但是,如果say()有無窮多或者足夠大的變化呢?
這時將有無窮變化的say()設計成介面類型——Java8中設計為函數介面則是合理的選擇。
常式 3 7無限可能package method.strategy;@FunctionalInterfacepublic interface SayStyle{ void say();}package method.strategy;public class Man{ private SayStyle say = null; public void setSayStyle(SayStyle say){ this.say = say; } public final void eat(){ System.out.println("用筷子"); } //每人說自己的方言 public void say(){ this.say.say(); }}package method.strategy;public class App{ public static void test(){ Man one = new Man(); //內容物件 SayStyle say = ()->{System.out.println("格老子");}; one.setSayStyle( say); one.say(); }}
此時,Man是環境類,它的使用者App需要依賴環境類Man和函數介面SayStyle。
雖然說函數介面的基本目標是實現回調,但是在非架構場合,代碼由客戶類提供也是函數介面的正常應用。畢竟回調只是分層結構中的術語,在非分層結構中,其代碼和普通多態沒有任何差異。
3.2.4 方法類型化