Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

methodichkaA5

.pdf
Скачиваний:
17
Добавлен:
02.02.2015
Размер:
801.83 Кб
Скачать

Эти основные характеристики могут влиять друг на друга. Например, состояние объекта может влиять на его поведение. (Если заказ "выполнен" или "оплачен", объект может отказаться выполнить вызов метода, требующего добавить или удалить предмет заказа. И наоборот, если заказ "пуст", т.е. ни один предмет не был заказан, он не может быть выполнен.).

В традиционной процедурно-ориентированной программе выполнение начинается сверху, с функции main. При разработке объектноориентированной системы понятие "верха" не существует, и часто возникает вопрос, с чего начинать. Ответ таков: "Сначала необходимо найти классы и добавить методы в каждый класс".

Классы представляют собой аналоги имен существительных в описании решаемой задачи, а методы - используемых при этом глаголов.

Например, при описании системы обработки заказов используются следующие имена существительные:

предмет;

заказ;

адрес доставки;

оплата;

счет.

Эти имена существительные соответствуют классам Item, Order и т.д. Рассмотрим теперь глаголы. Предметы заказываются. Заказы

выполняются или отменяются. Оплата заказа осуществляется. Используя эти глаголы, можно определить объект, выполняющий такие действия. Например, если поступил новый заказ, то ответственность за его обработку должен нести объект класса Order, поскольку именно в нем содержится информация о способе хранения и видах заказываемых предметов. Следовательно, в классе Order должен существовать метод add, получающий объект Item в качестве параметра.

6.4 Отношения между классами

Между классами существуют три обычных отношения.

Зависимость ("использует");

Агрегирование ("содержит");

Наследование ("является").

Отношение зависимости наиболее очевидное и распространенное. Например, класс Order (заказ) использует класс Account(счет), поскольку

51

объекты класса Order должны иметь доступ к объектам класса Account, чтобы проверить кредитоспособность заказчика. Однако класс Item (предмет) не зависит от класса Account, так как объекты класса Item никогда не интересуются состоянием счета заказчика. Следовательно, класс зависит от другого класса, если его методы манипулируют объектами этого класса.

Необходимо стараться минимизировать количество взаимозависимых классов. Если класс А не знает о существовании класса В, он тем более ничего не знает о любых его изменениях! (Это значит, что любые изменения, внесенные в класс В, не повлияют на класс А.) В терминах программного обеспечения это означает минимизацию связей (couplings) между классами.

Отношение агрегирования (aggregation) означает, что класс А содержит объекты класса В. Например, объект Order содержит объекты класса Item.

Наследование (inheritance) выражает отношение между конкретным и более общим классом. Например, класс RushOrder(срочный заказ) является производным от класса Order. Класс RushOrder имеет специальные методы для обработки приоритетов и разные методы для вычисления стоимости доставки, в то время как другие его методы, например, для заказа предмета и выписывания счета, унаследованы им от класса Order. В частности, если класс А расширяет класс В, то говорят, что класс А наследует методы класса В, имея, кроме них, еще и дополнительные возможности.

7.Использование существующих классов

7.1.Объекты и объектные переменные

Для примера рассмотрим класс Math. Как было показано, методы класса Math, например, метод Math.random, можно вызывать, ничего не зная о деталях их реализации. Для вызова метода достаточно знать его имя и параметры (если они есть).

Чтобы работать с объектами, их нужно сначала создать и задать их исходное состояние. Затем к этим объектам можно применять методы.

В языке Java для создания новых экземпляров используются конструкторы (constructors). Конструктор – это специальный метод, предназначенный для создания и инициализации объектов. Рассмотрим пример. Стандартная библиотека языка Java содержит класс Date. Его объекты описывают моменты времени, например "December 31, 1999, 23:59:59 GMP".

Имя конструктора всегда совпадает с именем класса. Следовательно, конструктор класса Date называется Date. Чтобы создать объект Date,

52

конструктор нужно соединить с оператором new, как показано в следующем

примере: new Date ().

Это выражение создает новый объект, который инициализируется текущими датой и временем.

Обычно объект необходимо как-то идентифицировать, чтобы использовать в дальнейшем. Для этого объект нужно присвоить переменной.

Date birthday = new Date();

birthday =

 

 

Date

 

 

 

 

 

 

 

 

Рисунок 8 – Объектная переменная birthday, ссылающаяся на вновь созданный объект

Между объектами и объектными переменными есть существенная разница. Например, оператор

Date deadline; // Переменная Deadline не ссылается ни на один объект

определяет объектную переменную deadline, которая может ссылаться на объекты типа Date. Важно понимать, что сама переменная deadline объектом не является и, по существу, даже не ссылается ни на один объект, поэтому ни один метод класса Date с помощью этой переменной вызывать пока нельзя. Оператор

s= deadline. toString(); // Вызывать метод еще рано.

//Приведет к сообщению об ошибке.

Сначала переменную deadline нужно инициализировать. Существует две возможности инициализации, переменную можно инициализировать вновь созданным объектом:

deadline = new Date();

Кроме того, можно заставить переменную ссылаться на существующий объект:

deadline = birthday;

Теперь обе переменные ссылаются на один и тот же объект.

53

birthday =

 

Date

 

 

 

deadline =

Рисунок 9 – Две объектные переменные ссылаются на один объект

Важно понимать, что объектная переменная фактически не содержит никакого объекта. Она лишь ссылается на объект.

В языке Java значение любой объектной переменной представляет собой ссылку на объект, размещенный где-то в другом месте. Оператор new также возвращает ссылку. Например, оператор

Date deadline = new Date();

состоит из двух частей. Выражение new Date () создает объект типа Date, а его значение представляет собой ссылку на этот вновь созданный объект.

Объектной переменной можно явно присвоить ссылку null, чтобы отметить тот факт, что эта переменная пока не ссылается ни на один объект.

deadline = null;

if(deadline != null)

System.out.println(deadline);

Если применить этот метод к переменной, значение которой равно null, то при выполнении программы возникнет ошибка.

birthday = null;

String s = birthday.toString(); // Ошибка!

Локальные объектные переменные не инициализируются автоматически ссылкой null. Программист должен сам инициализировать ее, либо, вызвав оператор new, либо присвоив ей значение null.

7.2.Класс GregorianCalendar из библиотеки языка Java

Впредыдущих примерах использовался класс Date, являющийся частью стандартной библиотеки языка Java. Экземпляр класса Date имеет состояние, а именно: конкретный момент времени.

Хотя при использовании класса Date необязательно знать о формате даты, отметим, что время представляется количеством миллисекунд (положительным или отрицательным), отсчитанным от фиксированного

54

момента времени, так называемой эпохи (epoch), т.е. от 00:00:00 UTC, 1 января 1970 года.

Оказывается, однако, что класс Date не очень удобен для манипулирования с датами. Разработчики библиотеки языка Java считали, что представление даты, например "December 31, 1999, 23:59:59", является совершенно произвольным и должно зависеть от календаря. Данное конкретное представление подчиняется григорианскому календарю, самому распространенному календарю в мире. Однако тот же самый момент времени совершенно иначе представляется в китайском или еврейском лунном календаре.

Разработчики библиотеки решили отделить вопросы, связанные с отслеживанием моментов времени, от вопросов их представления. Таким образом, стандартная библиотека языка Java содержит два отдельных класса: класс Date, представляющий момент времени, и класс GregorianCalendar, расширяющий более общий класс Calendar, описывающий свойства календаря в целом. Теоретически можно расширить класс Calendar и реализовать китайский лунный или марсианский календари. Однако в стандартной библиотеке, кроме григорианского календаря, нет никакой другой реализации.

Отделение измерения времени от календарей представляет собой хорошее объектно-ориентированное решение.

Класс Date содержит лишь небольшое количество методов, позволяющих сравнивать два момента времени. Например, методы before и after определяют, предшествует один момент времени другому или следует за ним.

if (today.before(birthday))

System.out.println("Еще есть время купить подарок.");

Класс GregorianCalendar содержит гораздо больше методов, чем класс Date. В частности, в нем есть несколько полезных конструкторов. Выражение new GregorianCalendar() создает новый объект, представляющий дату и момент времени, когда он был создан.

Можно создать объект, представляющий полночь указанной даты, год, месяц и день:

new GregorianCalendar(1999, 11, 31);

Довольно странно, что количество месяцев отсчитывается от нуля. Таким образом, число 11 означает декабрь. Для большей ясности можно использовать константу Calendar.DECEMBER.

new GregorianCalendar(1999, Calendar.DECEMBER, 31)

55

Кроме того, можно задать время:

new GregorianCalendar(1999, Calendar.DECEMBER, 31, 23, 59, 59);

Разумеется, как обычно, созданный объект нужно присвоить объектной переменной:

GregorianCalendar deadline = new GregorianCalendar(...);

Класс GregorianCalendar имеет инкапсулированные поля экземпляра, в которых записана указанная дата. Не видя исходный текст, невозможно определить, какое представление даты и времени использует этот класс. Разумеется, это совершенно неважно. Важно лишь то, какие методы класс предоставляет программисту.

7.3. Модифицирующие методы и методы доступа

Рассмотрим наиболее важные методы класса GregorianCalendar. Календарь должен вычислять атрибуты указанного момента времени,

например, дату, день недели, месяц или год. Чтобы получить одно из этих значений, можно использовать метод get из класса GregorianCalendar. Чтобы выбрать желаемый атрибут, нужно передать методу константу, определенную

в классе Calendar, например, Calendar.MONTH или Calendar.DAY_OF_WEEK:

GregorianCalendar now = new GregorianCalendar();

int month = now.get(Calendar.MONTH);

int day = now.get(Calendar.DAY_OF_WEEK);

Состояние объекта можно изменить с помощью методаset:

deadline.set(Calendar.YEAR, 2001);

deadline(Calendar.MONTH, Calendar.APRIL);

deadline.set(Calendar.DAY, 15);

Существует удобный способ установить год, месяц и день с помощью одного вызова:

deadline.set(2001, Calendar.APRIL, 15);

В заключение к заданной дате можно добавить количество дней, недель, месяцев и т.д.

deadline.add(Calendar.MONTH, 3); // Отодвинуть момент deadline на 3 месяца.

Если добавить отрицательное число, календарь передвинется назад. Между методом get с одной стороны и методами set и add с другой есть

принципиальная разница. Метод get только просматривает состояние объекта и сообщает о нем, в том время как методы set и add модифицируют состояние объекта. Методы, которые могут изменять поля экземпляра, называются

56

модифицирующими (mutators), a методы, которые могут лишь просматривать поля экземпляра, не изменяя их, называются методами доступа (accessors).

В именах методов доступа принято использовать префикс get, а в именах модифицирующих методов – префикс set. Например, класс GregorianCalendar для получения и установки момента времени, представленного объектом, имеет методы getTime и setTime соответственно.

Date time = calendar.getTime();

calendar.setTime(time);

Эти методы очень полезны для преобразований объектов класса GregorianCalendar в объекты класса Date, и наоборот. Например, известны год, месяц и день, и необходимо создать объект класса Date, поля которого были бы заполнены этими значениями. Поскольку класс Date ничего не знает о календарях, создадим сначала объект класса GregorianCalendar, а затем вызовем метод getTime для получения даты.

И, наоборот, если нужно определить год, месяц или день, записанные в объекте класса Date, создадим объект класса GregorianCalendar, установим время, а затем вызовем метод get.

GregorianCalendar calendar = new GregorianCalendar();

calendar.setTime(hireDay) ;

int year = calendar.get(Calendar.YEAR);

Пример.

Программа выводит на экран календарь текущего месяца. Текущий день помечен звездочкой, причем программа знает, как вычислить дни недели.

package testprj; import java.util.*;

public class CalendarTest{

public static void main(String[] args){

//Создаем объект d с текущей датой. GregorianCalendar d = new GregorianCalendar(); int today = d.get(Calendar.DAY_OF_MONTH); int month = d.get(Calendar.MONTH);

//Устанавливаем объект d на первую дату месяца. d.set(Calendar.DAY_OF_MONTH, 1);

int weekday = d.get(Calendar.DAY_OF_WEEK);

//Выводим на печать заголовок таблицы. System.out.println("Bc Пн Вт Ср Чт Пт Сб");

//Вставляем первую строку календаря.

for (int i = Calendar.SUNDAY; i < weekday; i++) System.out.print(" ");

57

do {

// Выводим на печать день.

int day = d.get(Calendar.DAY_OF_MONTH); if (day < 10)

System.out.print(" ");

System.out.print(day);

// Отметить текущий день звездочкой. if (day == today)

System.out.print("* ");

else

System.out.print(" ");

//После каждой субботы начинаем новую строку. if (weekday == Calendar.SATURDAY)

System.out.println ();

//Передвинуть объект d на новый день. d.add(Calendar.DAY_OF_MONTH, 1) ; weekday = d.get(Calendar.DAY_OF_WEEK);

}while(d.get(Calendar.MONTH) == month) ;

//Цикл завершается, когда объект d установлен

//на первый день следующего месяца.

//Выводим на экран последнюю строку. if(weekday != Calendar.SUNDAY)

System.out.println();

}

}

Результат работы программы представлен на рисунке 10.

Рисунок 10 – Результат работы программы testprj

58

Рассмотрим ключевые пункты этой программы. Во-первых, создается объект класса GregorianCalendar, инициализированный текущими датой и временем. (На самом деле в данном приложении время нас не интересует.).

GregorianCalendar d = new GregorianCalendar();

Затем необходимо определить текущий день и месяц, дважды вызвав метод get.

int today = d.get(Calendar.DAY_OF_MONTH);

int month = d.get(Calendar.MONTH);

После этого надо передать методу set объекта d параметр, задающий первый день текущего месяца, и получить день недели, соответствующий этой дате.

d.set(Calendar.DAY_OF_MONTH, 1) ;

int weekday = d.get(Calendar.DAY_OF_WEEK);

Переменная weekday полагается равной 1 (или Calendar.SUNDAY), если первый день месяца - воскресенье, 2 (или Calendar.MONDAY) - если понедельник, и т.д. Затем на экран выводится заголовок и пробелы, выравнивающие первую строку календаря. Для каждого дня выводится на экран пробел, если число меньше 10, затем-само число, а потом звездочка, если число соответствует сегодняшнему дню. Каждое воскресенье выводится с новой строки. Затем устанавливается объект d на следующий день:

d.add(Calendar.DAY_OF_MONTH, 1);

Когда же следует остановиться? Неизвестно, сколько в месяце дней: 31, 30, 29 или 28. Вместо этого необходимо продолжать итерации, пока объект d остается в пределах текущего месяца.

do {

}while (d.get(Calendar.MONTH) == month) ;

Как только объект d перейдет на следующий месяц, программа завершит свою работу.

Как видно, класс GregorianCalendar позволяет легко создавать программы для работы с календарем, с учетом таких сложностей, как вычисление дней недели и переменная продолжительность месяцев. Программист не обязан ничего знать о том, как именно класс GregorianCalendar вычисляет месяцы и дни недели. Нужно просто использовать методы get, set и add.

8.Создание собственных классов

Впредыдущих пунктах учебного пособия создавались простые классы. Все эти классы состояли из одного-единственного метода main. Теперь

59

подошло время научиться создавать "рабочие" классы, необходимые в более сложных приложениях. Обычно в этих классах нет метода main. Вместо этого у них есть собственные поля и методы. Чтобы написать полностью законченную программу, нужно объединить классы, один из которых имеет метод main.

Простейшее определение класса в языке Java имеет следующий вид.

class ИмяКласса {

 

свойство1;

(поле, некоторая глобальная переменная)

свойство2;

(переменная)

конcтруктор1;

(некоторая функция)

конструктор2;

(функция)

метод1;

(функция)

метод2;

(функция)

}

 

Пример.

В рамках некоторой системы необходимо разработать набор классов для хранения информации о треугольниках на плоскости. Известно, что треугольник состоит из трех точек. Поэтому начнем разработку проекта с создания класса Point, описывающего точку. Для этого в JBuilderX в проекте необходимо создать новый класс. Необходимо помнить, что название файла должно совпадать с названием класса.

package pname;

class Point {

float x;

float y;

Point() {

x=0;

y=0;

}

Point(float x, float y){ this.x=x;

this.y=y;

}

void setx(float x){ this.x=x;

}

void sety(float y){ this.y=y;

}

}

60

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]