К. Арнольд, Д. Гослинг - Язык программирования Java (1160779), страница 34
Текст из файла (страница 34)
Чтобы обеспечить правильность подсчетов, SortDouble содержит методы, используемые расширенными классами при выборкеданных или выполнении сравнений и перестановок.При проектировании класса нужно решить, в какой степени можно доверять порожденным классам. Класс SortDouble не доверяет им, и чащевсего при разработке классов, предназначенных для дальнейшего расширения, такой подход оправдывает себя. Безопасное проектирование нетолько предотвращает злонамеренное использование класса, но и борется с ошибками в программе.SortDouble тщательно ограничивает доступ к каждому члену класса до соответствующего уровня. Все неабстрактные методы объявляются final.Все они входят в контракт класса SortDouble, который подразумевает защиту алгоритма измерения от вмешательства извне. Объявлениеметодов с ключевым словом final помогает компилятору сгенерировать оптимальный код и предотвращает переопределение в порожденныхклассах.Объекты SortMetrics описывают параметры выполняемой сортировки.
Данный класс содержит три открытых поля. Его единственное назначениезаключается в передаче данных, так что скрывать данные за методами доступа нет смысла. SortDouble.metrics возвращает копию данных, чтобыне выдавать посторонним ссылку на свои внутренние данные. Благодаря этому предотвращается изменение данных как в коде, создающемобъекты Sort Double, так и в коде расширенных классов. Класс SortMetrics выглядит следующим образом:final class SortMetrics implements Cloneable {public long probeCnt,compareCnt,swapCnt;public void init() {probeCnt = swapCnt = compareCnt = 0;}public String toString() {return probeCnt + " probes " +compareCnt + " compares " +swapCnt + " swaps";}/** Данный класс поддерживает clone() */public Object clone() {try {return super.clone(); // механизм по умолчаниюcatch CloneNotSupportedException e) {// Невозможно: и this, и Object поддерживают clonethrow new InternalError(e.toString());}}}Приведем пример класса, расширяющего SortDouble.
Класс BubbleSort Double производит сортировку “пузырьковым методом” — чрезвычайнонеэффективный, но простой алгоритм сортировки, основное преимущество которого заключается в том, что его легко запрограммировать ипонять:class BubbleSortDouble extends SortDouble {protected void doSort() {for (int i = 0; i << dataLength(); i++) {for (int j = i + 1; j << dataLength(); j++) {if (compare(i, j) >> 0)swap(i, j);}}}static double[] testData = {0.3, 1.3e-2, 7.9, 3.17};static public void main(String[] args) {BubbleSortDouble bsort = new BubbleSortDouble();SortMetrics metrics = bsort.sort(testData);System.out.println("Bubble Sort: " + metrics);for (int i = 0; i << testData.length; i++)System.out.println("\t" + testData[i]);}}На примере метода main можно увидеть, как работает фрагмент программы, проводящий измерения: он создает объект класса, порожденного отSort Double, передает ему данные для сортировки и вызывает sort.
Метод sort инициализирует счетчики параметров, а затем вызываетабстрактный метод doSort. Каждый расширенный класс реализует свой вариант doSort для проведения сортировки, пользуясь в нужные моментыметодами dataLength, compare и swap. При возврате из функции doSort состояние счетчиков отражает количество выполненных операцийкаждого вида.BubbleSortDouble содержит метод main, в котором выполняется тестирование; вот как выглядят результаты его работы:Bubble Sort: 0 probes 6 compares 2 swaps0.0130.33.177.9Теперь давайте вернемся к рассмотрению проектирования классов, предназначенных для расширения.
Мы тщательно спроектировализащищенный интерфейс SortClass с расчетом на то, чтобы предоставить расширенным классам более тесный доступ к данным объекта — но лишьк тем из них, к которым нужно. Доступ к интерфейсам класса выбран следующим образом:●Открытый: члены класса с атрибутом public используются тестирующим кодом — то есть фрагментом программы, который вычисляетвременные затраты алгоритма. Примером может служить метод Bubble Sort.main; он предоставляет сортируемые данные и получаетрезультаты тестирования. К счетчикам из него можно обращаться только для чтения.
Открытый метод sort, созданный нами для тестовогокода, обеспечивает правильную инициализацию счетчиков перед их использованием.Объявляя метод doSort с атрибутом protected, тестирующий код тем самым разрешает обращаться к нему только косвенно, через главный методsort; таким образом мы можем гарантировать, что счетчики всегда будут инициализированы, и избежим возможной ошибки.Мы воспользовались методами и ограничением доступа, чтобы спрятать все, что выходит за пределы открытой части класса.
Единственное, чтоможет сделать с классом тестирующий код, — это выполнить тестирование для конкретного алгоритма сортировки и получить результат.●Защищенный: члены класса с атрибутом protected используются во время сортировки для получения измеренных параметров.Защищенный контракт позволяет алгоритму сортировки просмотреть и модифицировать данные с тем, чтобы получитьотсортированный список (средства для этого определяются алгоритмом).
Кроме того, такой способ предоставляет алгоритму сортировкиконтекст выполнения, в котором будут измеряться необходимые параметры (метод doSort).Мы договорились, что доверять расширенным классам в нашем случае не следует, — вот почему вся работа с данными осуществляется косвенно,через использование специальных методов доступа. Например, чтобы скрыть операции сравнения за счет отказа от вызова compare, алгоритмусортировки придется пользоваться методом probe для того, чтобы узнать, что находится в массиве.
Поскольку вызовы probe такжеподсчитываются, никаких незарегистрированных обращений не возникнет. Кроме того, метод metrics возвращает копию объекта со счетчиками,поэтому при сортировке изменить значения счетчиков невозможно.●Закрытый: закрытые данные класса должны быть спрятаны от доступа извне — конкретно, речь идет о сортируемых данных и счетчиках.Внешний код не сможет получить к ним доступ, прямо или косвенно.Как упоминалось выше, класс SortDouble проектировался так, чтобы не доверять расширенным классам и предотвратить любое случайное илинамеренное вмешательство с их стороны. Например, если бы массив SortDouble.
values (сортируемые данные) был объявлен protected вместоprivate, можно было бы отказаться от использования метода probe, поскольку обычно алгоритмы сортировки обходятся операциями сравненияи перестановки. Но в этом случае программист может написать расширенный класс, который будет осуществлять перестановку данных безиспользования swap. Результат окажется неверным, но обнаружить это будет нелегко. Подсчет обращений к данным и объявление массиваprivate предотвращает некоторые возможные программные ошибки.Если класс не проектируется с учетом его дальнейшего расширения, то он с большой вероятностью будет неправильно использоватьсяподклассами. Если же класс должен расширяться, следует особенно тщательно подойти к проектированию защищенного интерфейса (хотя врезультате, возможно, вам придется включить в него защищенные члены, если доступ из расширенных классов должен производитьсяспециальным образом).
В противном случае, вероятно, следует объявить класс final и спроектировать защищенный интерфейс, когда настанетвремя снять ограничение final.Упражнение 3.11Найдите в SortDouble по меньшей мере одну лазейку, которая позволяет алгоритму сортировки незаметно изменять значения измеренныхпараметров. Закройте ее. Предполагается, что автор алгоритма сортировки не собирается писать метод main.Упражнение 3.12Напишите универсальный класс SortHarness, который может сортировать объекты любого типа. Как в данном случае решается проблема супорядочением объектов — ведь для их сравнения нельзя будет пользоваться оператором <<?Содержание | Далее© 1997-2002 Издательский дом "Питер".
Авторские права охраняются.Предназначено только для частного использования!Воспроизведение материалов или частей данной книги в любом виде без письменного разрешения Издательского дома "Питер" запрещено!Глава 9ПОТОКИКак можно находиться в двух местах одновременно,если на самом деле вообще нигде не находишься?Firesign TheaterБольшинство программистов привыкло писать программы, которые выполняются шаг за шагом, в определенной последовательности. Наприведенной ниже иллюстрации показано, как извлекается банковский баланс, сумма на счету увеличивается и заносится обратно в запись осостоянии счета:Аналогичные действия выполняются как живыми банковскими работниками, так и компьютерными программами.
Подобная последовательностьдействий, выполняемых по одному, называется потоком (th read) . В большинстве языков программистам приходится иметь дело соднопоточной моделью программирования.Однако в настоящих банках подобные операции происходят одновременно. Несколько работников независимо друг от друга могут обновлятьсостояние банковских счетов:Аналог подобной ситуации в компьютере называется многопоточностью (multithreading). Поток (как и банковский работник) может работатьнезависимо от других потоков. И подобно тому, как двое банковских служащих могут пользоваться одними и теми же картотеками, потоки такжеосуществляют совместный доступ к объектам.Совместный доступ одновременно является и одним из самых полезных свойств многопоточности, и источников самых больших проблем.