Книга е още в много ранна фаза на написване



страница30/73
Дата25.07.2016
Размер13.53 Mb.
#6732
1   ...   26   27   28   29   30   31   32   33   ...   73

Интерфейс и реализация


Управлението на достъпа често се свързва със скриване на реализацията. Вграж­дането на данни и методи в класовете (комбинирано със скриване на реа­ли­зацията често наричано капсулиране) дава даннов тип с характеристики и по­ве­дение, но контролът на достъпа слага граници в този даннов тип по две важни при­чини. Първата е да се зададе какво клиентът програмист може и какво не мо­же да използва. Не може да изградите вътрешните механизми в структура и да очаквате клиент-програмиста да не я смята за част от интерфейса.

Това подхранва направо следващата причина, която е: да се раздели интерфейса от реализацията. Ако структурата се използва в няколко програми, като потре­би­телите могат само да изпращат съобщения до public интерфейса, тогава мо­же да се променя всичко което не е public (т.е. “приятелско,” protected или private) без да са необходими промени в техния код.

Сега сме в света на ООП, където class фактически описва “клас от обекти,” как­то бихте описали класа на рибите и класа на птиците (в биологията - бел.пр.). Все­ки обект от класа ще споделя единни характеристики и поведение. Класът е опи­сание на начина на действие и поведението на обектите от този клас.

В първия ООП език, Simula-67, ключовата дума class беше използвана за опи­са­ние на нов даннов тип. Същата дума се използва в повечето ООП езици. Фо­кус­на­та точка на целия език е: създаване на нови даннови типове които са повече от просто кутии за данни и методи.

Класът е фундаментална ОО концепция в Java. Това е една от ключовите думи коя­то няма да бъде с удебелени букви в тази книга – дразнещо става, ако се под­чертава толкова често срещене дума като “class.”

За яснота може да предпочетете маниер на създаване на класове при който public членовете са в началото, следвани от protected, friendly и private чле­но­ве­те. Хубавото е, че потребителят като започне да чете отгоре надолу ще срещ­не това, което му трябва първо (public членовете, понеже те могат да се викат из­вън файла) и ще спре да чете, когато види непублични членове, които са част от вътрешната реализация. Обаче с коментарите за документация поддържани от javadoc (описан в глава 2) въпросът за четимостта на програмите става по-мал­ко важен.

public class X {
public void pub1( ) { /* . . . */ }
public void pub2( ) { /* . . . */ }

public void pub3( ) { /* . . . */ }


private void priv1( ) { /* . . . */ }
private void priv2( ) { /* . . . */ }
private void priv3( ) { /* . . . */ }
private int i;
// . . .
}

Това може да помогне на четенето само частично, защото все още интерфейсът и реализацията са смесени. Тоест все още се вижда сорсът – реализацията – по­не­же си е в класа. Извеждането на интерфейса за потребителя на класа си е ра­бо­та на class browser-а, инструмент, чиято работа е да гледа класовете и да ви по­каз­ва какво може да правите с тях (т.е. какви членове имат) по полезен на­чин. Когато четете тази книга, добри обектни броузъри трябва да се обакват във всички добри Java среди за развой.


Достъп до клас


В Java спецификаторите на достъпа може да се използват и за да се посочи кои кла­сове в библиотека ще бъдат достъпни за потребителите на същата би­блио­те­ка. Ако искате клас да бъде достъпен за клиент-програмиста слагате ключовата ду­ма public някъде преди отварящата фигурна скоба на тялото на класа. Това управ­лява даже дали клиентът може да създаде обект от класа.

За да се управлява достъпът до клас, спецификаторът трябва да се появи преди class. Така може да се напише:

public class Widget {

Тоест името на библиотеката е mylib и всеки клиент може да има достъп до Widget чрез

import mylib.Widget;

или


import mylib.*;

Има обаче двойка допълнителни ограничения:



  1. Може да има само един public за компилационна единица (файл). Идеята е че всяка компилационна единица има единствен интерфейс представян от то­зи клас. Може да има колкото трябват “приятелски” спомагателни кла­со­ве. Ако имате повече от един public в компилационната единица ком­пи­ла­то­рът ще издаде съобщение за грешка.

  2. Името на public класа трябва точно да съвпада с името на ком­пи­ла­цион­на­та единица, която го съдържа, включително капитализацията. Така за Widget името на файла трябва да е Widget.java, не widget.java или WIDGET.java. Ще излезе грешка при компилация ако те не съвпадат.

  3. Възможно е, макар и да не е типично, да има компилационна единица без ни­какъв публичен клас. В този случай може да я наречете както желаете.

Какво ако сте вкарали клас в mylib който използвате за изпълнение на работите на Widget или друг public клас в mylib? Не искате да правите документация за кли­ент-програмист и смятате след време да промените нещата и да махнете из­ця­ло този клас, замествайки го с друг. За да имате тази гъвкавост трябва да оси­гу­рите че клиент-програмистът не зависи от конкретната реализация скрита в mylib. За да се направи това махате public ключовата дума от класа, с което той става приятелски. (Такъв клас може да се използва само в пакета.)

Забележете че клас не може да бъде private (което ще го направи недостъпен за всич­ко освен за него), или protected.4 Така че имате два избора за достъп до клас: “приятелски” или public. Ако не искате никой да има достъп до този клас, мо­же да направите всички конструктори private, предотвратявайки всеки освен вас, от static член на класа, да може да направи обект.5 Ето пример:

//: c05:Lunch.java

// Demonstrates class access specifiers.

// Make a class effectively private

// with private constructors:


class Soup {

private Soup() {}

// (1) Allow creation via static method:

public static Soup makeSoup() {

return new Soup();

}

// (2) Create a static object and



// return a reference upon request.

// (The "Singleton" pattern):

private static Soup ps1 = new Soup();

public static Soup access() {

return ps1;

}

public void f() {}



}
class Sandwich { // Uses Lunch

void f() { new Lunch(); }

}
// Only one public class allowed per file:

public class Lunch {

void test() {

// Can't do this! Private constructor:

//! Soup priv1 = new Soup();

Soup priv2 = Soup.makeSoup();

Sandwich f1 = new Sandwich();

Soup.access().f();

}

} ///:~


До сега повечето от методите връщаха или void или първичен тип, така че дефиницията:

public static Soup access() {

return ps1;

}

може да изглежда малко смущаваща на пръв поглед. Думата преди името на ме­то­да (access) казва какво той връща. До тук най-често това беше void, което зна­чи че не връща нищо. Но също би могло да се върне манипулатор на обект, как­то е в случая. Този метод връща манипулатор на обект Soup.



Класът Soup показва как да се избегне възможността за непосредствено съз­да­ва­не на обекти като се направят всички конструктори private. Помнете че ако не направите явно поне един конструктор, конструктор по подразбиране (кон­струк­тор без аргументи) ще бъде създаден автоматично. Като напишете кон­струк­тор по подразбиране той няма да се саздаде автоматично. Като го на­пра­ви­те private никой не може да създаде обект от него клас. Но как може да се из­полз­ва класа? Горният пример показва две възможности. Първо, static метод да се саздаде, който създава Soup и връща манипулатор към него. Това може да бъ­де полезно ако изпълнявате допълнителни операции над Soup преди да го вър­нете, или искате да запазите броя на създаваните Soup обекти (може би за ре­гистрация на популацията им).

Втората възможност използва т.н. design pattern, което ще се дискутира по-къс­но в тази книга. Този конкретно шаблон се нарича “singleton” понеже позволява да се създаде само един обект изобщо. Обектът от клас Soup се създава котж static private член на Soup, така че има един и само един и не може да се до­бе­ре­те до него освен с public метода access( ).

Както вече беше споменато, ако не сложите спецификатор за достъп той става по подразбиране “приятелски.” Това значи че обект от този клас може да се съз­даде от всеки друг клас в пакета, но не и от клас извън него. (Помнете, всич­ки­те файлове в една директория които нямат явни package декларации са неяв­но част от пакета по подразбиране за същата директория.) Обаче ако static член от този клас е public, клиент-програмистът има достъп до static члена въпреки че не може да създаде обект от този клас.




Сподели с приятели:
1   ...   26   27   28   29   30   31   32   33   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница