Е. К. Пугачев Объектно-ориентированное программирование Под общей редакцией Ивановой Г. С. Рекомендовано Министерством общего и профессионального образования Российской Федерации в качестве учебник

Вид материалаУчебник

Содержание


2.6.Композиция и наполнение
Пример 2.27. Использование объектных полей
Program Compos
Procedure Print
End; Procedure Win.Init
Пример 2.28.
Program MoveCir
Procedure Out
Procedure Control
Procedure CrCr(P1,P2:Cp)
End; Var i,j:integer
Clrscr; Writeln('Введите:':20)
Write('размер зоны по оси Y - '); readln(ly)
Write('задержку - '); readln(d)
Подобный материал:
1   ...   10   11   12   13   14   15   16   17   ...   39
^

2.6.Композиция и наполнение


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

Композицией называется такое отношение между классами, когда один является частью второго.

Композиция реализуется включением в класс объектных полей и применяется в тех случаях, когда наследование по каким-либо причинам невозможно или не целесообразно.

Borland Pascal 7.0 предоставляет возможность использования в классах объектных полей. Рассмотрим это на примере.

^ Пример 2.27. Использование объектных полей

Ниже приведен текст программы, в которой класс Выводимая строка (OutS) объявлен как часть класса Окно (Win). Это реализовано включением в структуру класса Win объектного поля Ob_Field.

^ Program Compos;

Uses Crt;

Type

OutS = Object {класс Выводимая строка}

S:string; {строка вывода}

Cs:byte; {цвет символов строки}

Procedure Init(Sn:string;Csn:byte); {инициализация полей}

^ Procedure Print; {вывод строки}

End;

Procedure OutS.Init; Begin S:=Sn; Cs:=Csn End;

Procedure OutS.Print; Begin Textcolor(Cs); Write(S) End;

Type

Win = Object {класс Окно}

X1,Y1,X2,Y2, {координаты окна}

Cf:byte; {цвет фона}

Ob_Field : OutS; {статическое объектное поле}

Procedure Init(Xn1,Yn1,Xn2,Yn2,Cfn:byte;Obn:OutS);

Procedure MakeWin; {изображение окна}

^ End;

Procedure Win.Init;

Begin X1:=Xn1; Y1:=Yn1; X2:=Xn2; Y2:=Yn2; Cf:=Cfn;

Ob_Field:=Obn; {инициализация объектного поля }

End;

Procedure Win.MakeWin;

Begin

Window(X1,Y1,X2,Y2); Textbackground(Cf); Clrscr;

Ob_Field.Print; {обращение к методу Print класса OutS как к методу поля класса Win}

End;

Var V:Win; F:OutS; {объявление экземпляров классов}

Begin

F.Init('Объектное поле',1); {инициализировать объекты}

V.Init(20,10,35,10,0,F); {F – параметр-объект}

V.MakeWin; {изобразить окна и вывести строку}

Readkey;

End.

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

^ Пример 2.28. Использование полей - указателей на объекты

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



Рис. 2.39. Вид экрана при выполнении программы «Окружности»

В программе осуществляется анализ на столкновение всех окружностей друг с другом и с зоной. При столкновении окружности меняют направление движения «оттолкнувшись» друг от друга.

Диаграмма объектов для данного примера представлена на рис.2.7.



Рис. 2.40. Диаграмма объектов программы «Окружности»

Для реализации объектов программы потребуются классы: Zona (зона) и Cir (окружность). Класс Zona будет включать поля, определяющие размер зоны на экране, поле N – для хранения количества окружностей и поле P - массив указателей на объекты класса Cir. Он также будет включать методы инициализации Init, изображения зоны Out и перемещения окружностей Run. Удобно определить внутренний метод Control, который будет определять наличие столкновений всех созданных объектов-окружностей друг с другом и зоной (рис.2.8).

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



Рис. 2.41. Диаграмма классов программы «Окружности»

Рассмотрим работу программы, акцентируя внимание на использовании полей указателей на объекты.

В начале задаются параметры зоны, и определяется количество размещаемых окружностей. Далее инициализируются объекты типа Cir и объект типа Zona. В результате полю P объекта Z будет передан массив указателей на объекты типа Cir.

В методе Control объекта Z отслеживается ситуация возможного столкновения друг с другом всех созданных экземпляров классов. Если прогноз на столкновение каких-либо объектов для следующего шага положительный, то метод Control изменяет направление движения окружностей. Такое управление становится возможным благодаря использованию указателей, переданных объекту типа Zona.

^ Program MoveCir;

Uses graph,crt;

Type

Cp=^Cir; {указатель на класс}

Cir=Object {класс Окружность}

X,Y,R,C, {координаты центра, радиус и цвет окружности}

Dx,Dy:integer; {шаг перемещения}

Constructor Init(Xn,Yn,Rn,Cn,Dxn,Dyn:integer); {конструктор}

^ Procedure Out; {изображение окружности}

Procedure Move; {перемещение окружности}

End;

Constructor Cir.Init;

Begin R:=Rn; C:=Cn; Dx:=Dxn; Dy:=Dyn; X:=Xn; Y:=Yn End;

Procedure Cir.Out;

Begin Setcolor(C); Circle(X,Y,R) End;

Procedure Cir.Move;

Var cc:integer;

Begin cc:=C; C:=Getbkcolor; Out; C:=cc; X:=X+Dx; Y:=Y+Dy; Out;

End;

Type

mascp=array [1..100] of Cp; {массив указателей}

Zona=Object {класс Зона}

X,Y,Lx,Ly, {координаты верхнего левого угла и размеры зоны}

C:word; {цвет зоны}

P:mascp; {поле - массив указателей}

N:byte; {количество окружностей}

Constructor Init(Xn,Yn,Lxn,Lyn,Cn:word;Pn:mascp;Nn:byte);

Procedure Out; {изображение зоны}

^ Procedure Control; {проверка объектов на столкновение}

Procedure Run; {перемещение окружностей}

End;

Constructor Zona.Init;

Begin X:=Xn; Y:=Yn; Lx:=Lxn; Ly:=Lyn; C:=Cn; P:=Pn; N:=Nn End;

Procedure Zona.Out;

Begin Setcolor(C); Rectangle(X,Y,X+Lx,Y+Ly) End;

Procedure Zona.Control;

{Прогноз на столкновение двух окружностей}

^ Procedure CrCr(P1,P2:Cp);

Var wx,wy:real;

Begin wx:=P1^.X+P1^.Dx-P2^.X-P2^.Dx;

wy:=P1^.Y+P1^.Dy-P2^.Y-P2^.Dy;

if (sqrt(sqr(wx)+ sqr(wy)) <= P2^.R+P1^.R) then

begin {смена направления перемещения}

P1^.Dx:=-P1^.Dx; P2^.Dx:=-P2^.Dx;

P1^.Dy:=-P1^.Dy; P2^.Dy:=-P2^.Dy;

end;

End;

{Прогноз на столкновение окружности с зоной}

Procedure CrZn(P:Cp);

Begin

if (P^.X+P^.Dx-P^.R <= X) or (P^.X+P^.Dx+P^.R >= X+Lx)

then P^.Dx:=-P^.Dx; {смена направления движения по X}

if (P^.Y+P^.Dy-P^.R <= Y) or (P^.Y+P^.Dy+P^.R >= Y+Ly)

then P^.Dy:=-P^.Dy; {смена направления движения по Y}

^ End;

Var i,j:integer;

Begin

{Проверка на столкновение всех окружностей друг с другом}

for i:=1 to N-1 do for j:=i to N do CrCr(P[i],P[j]);

{Проверка на столкновение с зоной всех окружностей}

for i:=1 to N do CrZn(P[i]);

End;

Procedure Zona.Run;

Var k:integer;

Begin Control; {вызвать метод проверки на столкновение}

for k:=1 to n do P[k]^.Move;

End;

{ основная программа }

Var Z:Zona; {объект класса Zona}

V:mascp; {массив указателей на класс Окружность}

a,rg,k,d,i, {вспомогательные переменные}

x,y,lx,ly,lmin,cz, {параметры зоны}

n,nmax, {max и текущее количество окружностей}

xc,yc,cc, {координаты центра и цвет окружности}

r,rm, {текущий и максимальный радиус}

dx,dy:integer; {шаг перемещения окружности по осям}

Begin

^ Clrscr; Writeln('Введите:':20);

Write('координату верхнего левого угла зоны по X - '); readln(x);

Write('координату верхнего левого угла зоны по Y - '); readln(y);

Write('размер зоны по оси X - '); readln(lx);

^ Write('размер зоны по оси Y - '); readln(ly);

cz:=random(14)+1; {цвет зоны}

if lx<=ly then lmin:=lx else lmin:=ly;

rm:=random(round(lmin/2))+3; {max радиус}

nmax:=sqr(round(lmin/(2*rm+1))); if nmax>100 then nmax:=100;

Write('количество окружностей (не более ',nmax,' ) - '); readln(n);

^ Write('задержку - '); readln(d);

xc:=x+rm+1; yc:=y+rm+1; k:=n;

while k>0 do

begin {инициализация окружностей}

r:=random(rm)+1; cc:=random(15)+1;

repeat dx:=random(5)-3 until dx<>0;

repeat dy:=random(5)-3 until dy<>0;

if (xc+rm+1) < (x+lx) then

begin New(V[k]); V[k]^.Init(xc,yc,r,cc,dx,dy); {окружности}

dec(k); xc:=xc+2*rm+1

end

else if (yc+rm+1)< (y+ly) then

begin yc:=yc+2*rm+1; xc:=x+rm+1 end;

end;

a:=Detect; Initgraph(a,rg,'C:\TP\BGI');

Z.Init(x,y,lx,ly,cz,V,n); {инициализировать зону}

Z.Out; {отобразить зону}

repeat

Z.Run; {вызвать метод движения окружностей}

for i:=1 to 10 do delay(d);

until Keypressed;

Closegraph;

End.