@@ -760,22 +760,265 @@ Woodwind.play() MIDDLE_C
760760
761761## 抽象类和接口
762762
763+ 尤其是在 Java 8 引入 ** default** 方法之后,区分何时抽象类还是接口是最好的选择变得更加令人困惑。下表做了明确的区分:
763764
765+ | 特性 | 接口 | 抽象类 |
766+ | :------------------: | :--------------------------------------------------------: | :--------------------------------------: |
767+ | 组合 | 新类可以组合多个接口 | 只能继承单一抽象类 |
768+ | 状态 | 不能包含属性(除了静态属性,不支持对象状态) | 可以包含属性,非抽象方法可能引用这些属性 |
769+ | 默认方法 和 抽象方法 | 不需要在子类中实现默认方法。默认方法可以引用其他接口的方法 | 必须在子类中实现抽象方法 |
770+ | 构造器 | 没有构造器 | 可以有构造器 |
771+ | 可见性 | 隐式 ** public** | 可以是 ** protected** 或友元 |
764772
773+ 抽象类仍然是一个类,在创建新类时只能继承它一个。而创建类的过程中可以实现多个接口。
774+
775+ 有一条实际经验:尽可能地抽象。因此,更倾向使用接口而不是抽象类。只有当必要时才使用抽象类。除非必须使用,否则不要用接口和抽象类。大多数时候,普通类已经做得很好,如果不行的话,再移动到接口或抽象类中。
765776
766777<!-- Complete Decoupling -->
778+
767779## 完全解耦
768780
781+ 当方法操纵的是一个类而非接口时,它就只能作用于那个类或其子类。如果想把方法应用于那个继承层级结构之外的类,就会触霉头。接口在很大程度上放宽了这个限制,因而使用接口可以编写复用性更好的代码。
782+
783+ 例如有一个类 ** Process** 有两个方法 ` name() ` 和 ` process() ` 。` process() ` 方法接受输入,修改并输出。把这个类作为基类用来创建各种不同类型的 ** Processor** 。下例中,** Processor** 的各个子类修改 String 对象(注意,返回类型可能是协变类型而非参数类型):
784+
785+ ``` java
786+ // interfaces/Applicator.java
787+ import java.util.* ;
788+
789+ class Processor {
790+ public String name () {
791+ return getClass(). getSimpleName();
792+ }
793+
794+ public Object process (Object input ) {
795+ return input;
796+ }
797+ }
798+
799+ class Upcase extends Processor {
800+ // 返回协变类型
801+ @Override
802+ public String process (Object input ) {
803+ return ((String ) input). toUpperCase();
804+ }
805+ }
806+
807+ class Downcase extends Processor {
808+ @Override
809+ public String process (Object input ) {
810+ return ((String ) input). toLowerCase();
811+ }
812+ }
813+
814+ class Splitter extends Processor {
815+ @Override
816+ public String process (Object input ) {
817+ // split() divides a String into pieces:
818+ return Arrays . toString(((String ) input). split(" " ));
819+ }
820+ }
821+
822+ public class Applicator {
823+ public static void apply (Processor p , Object s ) {
824+ System . out. println(" Using Processor " + p. name());
825+ System . out. println(p. process(s));
826+ }
827+
828+ public static void main (String [] args ) {
829+ String s = " We are such stuff as dreams are made on" ;
830+ apply(new Upcase (), s);
831+ apply(new Downcase (), s);
832+ apply(new Splitter (), s);
833+ }
834+ }
835+ ```
836+
837+ 输出:
838+
839+ ```
840+ Using Processor Upcase
841+ WE ARE SUCH STUFF AS DREAMS ARE MADE ON
842+ Using Processor Downcase
843+ we are such stuff as dreams are made on
844+ Using Processor Splitter
845+ [We, are, such, stuff, as, dreams, are, made, on]
846+ ```
847+
848+ ** Applicator** 的 ` apply() ` 方法可以接受任何类型的 ** Processor** ,并将其应用到一个 ** Object** 对象上输出结果。像本例中这样,创建一个能根据传入的参数类型从而具备不同行为的方法称为* 策略* 设计模式。方法包含算法中不变的部分,策略包含变化的部分。策略就是传入的对象,它包含要执行的代码。在这里,** Processor** 对象是策略,` main() ` 方法展示了三种不同的应用于 ** String s** 上的策略。
849+
850+ ` split() ` 是 ** String** 类中的方法,它接受 ** String** 类型的对象并以传入的参数作为分割界限,返回一个数组 ** String[ ] ** 。在这里用它是为了更快地创建 ** String** 数组。
851+
852+ 假设现在发现了一组电子滤波器,它们看起来好像能使用 ** Applicator** 的 ` apply() ` 方法:
853+
854+ ``` java
855+ // interfaces/filters/Waveform.java
856+ package interfaces.filters ;
857+
858+ public class Waveform {
859+ private static long counter;
860+ private final long id = count++ ;
861+
862+ @Override
863+ public String toString () {
864+ return " Waveform " + id;
865+ }
866+ }
867+
868+ // interfaces/filters/Filter.java
869+ package interfaces.filters ;
870+
871+ public class Filter {
872+ public String name () {
873+ return getClass(). getSimpleName();
874+ }
875+
876+ public Waveform process (Waveform input ) {
877+ return input;
878+ }
879+ }
880+
881+ // interfaces/filters/LowPass.java
882+ package interfaces.filters ;
883+
884+ public class LowPass extends Filter {
885+ double cutoff;
886+
887+ public LowPass (double cutoff ) {
888+ this . cutoff = cutoff;
889+ }
890+
891+ @Override
892+ public Waveform process (Waveform input ) {
893+ return input; // Dummy processing 哑处理
894+ }
895+ }
896+
897+ // interfaces/filters/HighPass.java
898+ package interfaces.filters ;
899+
900+ public class HighPass extends Filter {
901+ double cutoff;
902+
903+ public HighPass (double cutoff ) {
904+ this . cutoff = cutoff;
905+ }
906+
907+ @Override
908+ public Waveform process (Waveform input ) {
909+ return input;
910+ }
911+ }
912+
913+ // interfaces/filters/BandPass.java
914+ package interfaces.filters ;
915+
916+ public class BandPass extends Filter {
917+ double lowCutoff, highCutoff;
918+
919+ public BandPass (double lowCut , double highCut ) {
920+ lowCutoff = lowCut;
921+ highCutoff = highCut;
922+ }
923+
924+ @Override
925+ public Waveform process (Waveform input ) {
926+ return input;
927+ }
928+ }
929+ ```
930+
931+ ** Filter** 类与 ** Processor** 类具有相同的接口元素,但是因为它不是继承自 ** Processor** —— 因为 ** Filter** 类的创建者根本不知道你想将它当作 ** Processor** 使用 —— 因此你不能将 ** Applicator** 的 ` apply() ` 方法应用在 ** Filter** 类上,即使这样做也能正常运行。主要是因为 ** Applicator** 的 ` apply() ` 方法和 ** Processor** 过于耦合,这阻止了 ** Applicator** 的 ` apply() ` 方法被复用。另外要注意的一点是 Filter 类中 ` process() ` 方法的输入输出都是 ** Waveform** 。
932+
933+ 但如果 ** Processor** 是一个接口,那么限制就会变得松动到足以复用 ** Applicator** 的 ` apply() ` 方法,用来接受那个接口参数。下面是修改后的 ** Processor** 和 ** Applicator** 版本:
934+
935+ ``` java
936+ // interfaces/interfaceprocessor/Processor.java
937+ package interfaces.interfaceprocessor ;
938+
939+ public interface Processor {
940+ default String name () {
941+ return getClass(). getSimpleName();
942+ }
943+
944+ Object process (Object input );
945+ }
946+
947+ // interfaces/interfaceprocessor/Applicator.java
948+ package interfaces.interfaceprocessor ;
949+
950+ public class Applicator {
951+ public static void apply (Processor p , Object s ) {
952+ System . out. println(" Using Processor " + p. name());
953+ System . out. println(p. process(s));
954+ }
955+ }
956+ ```
957+
958+ 复用代码的第一种方式是客户端程序员遵循接口编写类,像这样:
959+
960+ ``` java
961+ // interfaces/interfaceprocessor/StringProcessor.java
962+ // {java interfaces.interfaceprocessor.StringProcessor}
963+ package interfaces.interfaceprocessor ;
964+ import java.util.* ;
965+
966+ interface StringProcessor extends Processor {
967+ @Override
968+ String process (Object input ); // [1]
969+ String S = " If she weighs the same as a duck, " + " she's made of wood" ; // [2]
970+
971+ static void main (String [] args ) { // [3]
972+ Applicator . apply(new Upcase (), S );
973+ Applicator . apply(new Downcase (), S );
974+ Applicator . apply(new Splitter (), S );
975+ }
976+ }
977+
978+ class Upcase implements StringProcessor {
979+ // 返回协变类型
980+ @Override
981+ public String process (Object input ) {
982+ return ((String ) input). toUpperCase();
983+ }
984+ }
985+
986+ class Downcase implements StringProcessor {
987+ @Override
988+ public String process (Object input ) {
989+ return ((String ) input). toLowerCase();
990+ }
991+ }
992+
993+ class Splitter implements StringProcessor {
994+ @Override
995+ public String process (Object input ) {
996+ return Arrays . toString(((String ) input). split(" " ));
997+ }
998+ }
999+ ```
1000+
1001+ 输出:
1002+
1003+ ```
1004+ Using Processor Upcase
1005+ IF SHE WEIGHS THE SAME AS A DUCK, SHE'S MADE OF WOOD
1006+ Using Processor Downcase
1007+ if she weighs the same as a duck, she's made of wood
1008+ Using Processor Splitter
1009+ [If, she, weighs, the, same, as, a, duck,, she's, made, of, wood]
1010+ ```
7691011
7701012<!-- Combining Multiple Interfaces -->
1013+
7711014## 多接口结合
7721015
7731016
7741017<!-- Extending an Interface with Inheritance -->
7751018## 使用继承扩展接口
7761019
777-
7781020<!-- Adapting to an Interface -->
1021+
7791022## 接口适配
7801023
7811024
0 commit comments