Эккель Брюс
Шрифт:
public String nameO {
return getClassO getSimpleName.
}
public Waveform process(Waveform input) { return input; } } III ~
// interfaces/filters/LowPass java package interfaces filters,
public class LowPass extends Filter { double cutoff;
public LowPass(double cutoff) { this.cutoff = cutoff; } public Waveform process(Waveform input) {
return input; II Фиктивная обработка
}
} Hill i nterfaces/fi 1ters/Hi ghPass.java package interfaces.filters;
public class HighPass extends Filter { double cutoff;
public HighPass(double cutoff) { this.cutoff = cutoff; } public Waveform process(Waveform input) { return input. } } ///.-
// interfaces/filters/BandPass java package interfaces filters;
public class BandPass extends Filter { double lowCutoff. highCutoff; public BandPass(double lowCut. double highCut) { lowCutoff = lowCut; highCutoff = highCut;
}
public Waveform process(Waveform input) { return input; } } III-
Класс Filter содержит те же интерфейсные элементы, что и Processor, но, поскольку он не является производным от Processor (создатель класса Filter и не подозревал, что вы захотите использовать его как Processor), он не может использоваться с методом Apply.process, хотя это выглядело бы вполне естественно. Логическая привязка между Apply.process и Processor оказывается более сильной, чем реально необходимо, и это обстоятельство препятствует повторному использованию кода Apply.process. Также обратите внимание, что входные и выходные данные относятся к типу Waveform.
Но, если преобразовать класс Processor в интерфейс, ограничения ослабляются и появляется возможность повторного использования Apply.process. Обновленные версии Processor и Apply выглядят так:
//: interfaces/interfaceprocessor/Processor.java package interfaces interfaceprocessor;
public interface Processor { String nameO;
Object process(Object input), } ///-
//. interfaces/interfaceprocessor/Apply.java package i nterfaces.i nterfaceprocessor, import static net mindview.util.Print.*:
public class Apply {
public static void process(Processor p. Object s) { print ("Using Processor " + p.nameO): print(p.process(s)):
}
} ///:-
В первом варианте повторного использования кода клиентские программисты пишут свои классы с поддержкой интерфейса:
//: interfaces/interfaceprocessor/StringProcessor.java package i nterfaces.i nterfaceprocessor; import java.util.*;
public abstract class StringProcessor implements Processor! public String nameO {
return getClassO getSimpleNameO;
}
public abstract String process(Object input); public static String s =
"If she weighs the same as a duck, she's made of wood"; public static void main(String[] args) { Apply, process (new UpcaseO, s); Apply, process (new DowncaseO, s); Apply, process (new SplitterO. s);
class Upcase extends StringProcessor {
public String process(Object input) { II Ковариантный возвращаемый тип return ((String)input) .toUpperCaseO;
class Downcase extends StringProcessor { public String process(Object input) {
return ((String)input).toLowerCase;
class Splitter extends StringProcessor {
public String process(Object input) {
return Arrays.toString(((String)input).split(" ")).
}
} /* Output
Используем Processor Upcase
IF SHE WEIGHS THE SAME AS A DUCK, SHE'S MADE OF WOOD Используем Processor Downcase if she weighs the same as a duck, she's made of wood Используем Processor Splitter
[If. she. weighs, the. same. as. a. duck., she's, made. of. wood] *///:-
Впрочем, довольно часто модификация тех классов, которые вы собираетесь использовать, невозможна. Например, в примере с электронными фильтрами библиотека была получена из внешнего источника. В таких ситуациях применяется паттерн «адаптер»: вы пишете код, который получает имеющийся интерфейс, и создаете тот интерфейс, который вам нужен:
//: interfaces/interfaceprocessor/FilterProcessor java package interfaces interfaceprocessor, import interfaces.filters.*;
class FilterAdapter implements Processor { Filter filter.