首页 > 代码库 > 3.2.4 方法类型化
3.2.4 方法类型化
方法类型化——将某个或某些方法(准确的说,是方法头或接口) 提升为类型,是方法型模式的共同技术基础和设计思路。
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; @FunctionalInterface public 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 方法类型化