Вероятно Аристотел пръв е изследвал понятието "тип". Известно е, че той е говорил за “класа на рибите и класа на птиците.” Концепцията че, макар да са уникални, обектите имат общи свойства с други обекти, е използувана в първия ООП език, Simula-67, с неговата основна ключова дума class която въвежда в програмата нов тип (така клас и тип се употребяват често като синоними3).
Simula, както предполага името, беше създаден за симулация на ситуации като в класическия “проблем на банковия касиер.” В него има много касиери, клиенти, сметки, транзакции и т.н.. Членовете (елементите) от всеки клас имат общи неща помежду си: всяка сметка има баланс, every teller всеки касиер може да приема депозити и т.н. В същото време всеки член има негово конкретно собствено състояние; всяка сметка има свой си баланс, всеки касиер си има име. Така касиерите, клиентите, сметките, транзакциите и т.н. могат да бъдат представени всяка с отделна същност в компютърна програма. Тази същност е обект и всеки обект принадлежи на клас, който определя чертите и поведението.
Така, въпреки че се създават нови типове, практически всички ООП езици използуват ключовата дума “class”. Когато видите “тип” мислите “клас” и обратно.
Като създадете веднъж типа, може да създавате и манипулирате колкото си искате обекти от полето на решавания проблем. Разбира се, едно от предизвикателството на ООП е да се създаде едно-към-едно изображение между нещата от проблемното пространство (мястото където проблемът фактически съществува) и пространството на решението (мястото, където моделирате проблема, като компютър например).
Как обаче караме обекта да върши полезна работа? Трябва да има начин да му се поръча да свърши нещо полезно, като да извърши транзакция, начертае нещо на екран или включи верига. Всеки обект може да удовлетвори само определени поръчки. Поръчките към обекта са определени от неговия интерхейс и тиха, който определя интерфейса. Идеята типът да бъде еквивалентен на интерфейса е основна за ООП.
Light
on( )
off( )
brighten( )
dim( )
Type Name
Interface
Прост пример може да бъде представяне на електрическата крушка:
Light lt = new Light();
lt.on();
Името на типа/класа е Light и поръчките, които може да давате на обекта Light са да включвате, изключвате, усилвате или намалявате светлината. Вие създавате “дръжка” за Light просто декларирайки име (lt) за нея и построявате обекта Light с ключовата дума new , приравнявайки я към дръжката (някои биха предпочели "манипулатор" - б.пр.) със знака = . За да се изпрати съобщение на обекта споменавате името на дръжката, следвано от името на операцията, разделени с точка ("."). От мястото на програмист, работещ с предварително създадени класове това изглежда (и е) напълно достатъчно за ООП работа.
Скриване на код
Полезно е да се разделят ролите на създатели на класове (тези които създават класове) и програмисти-клиенти4 ("консуматори" на класове), които ги използуват в своите програми). Целта на последните е да съберат пълно сандъче с инструменти, които да използват за бързо писане на приложения. Целта на създателя на класове е да остави видимо само най-необходимото видимо и да скрие всичко останало. Защо? Ако е скрито, клиентът не може да го използува, което значи, че създателят на класа може да го променя, без това да влияе на когото и да било друг.
Интерфейсът задава какви какви поръчки може да отправяте към конкретен обект. Трябва обаче някъде да има код, който да изпълни поръчката. Така заедно със скритите данни върви и приложението. От процедурна гледна точка това не е толкова сложно. Всеки тип има функция, асоциирана с конкретна възможна поръчка и когато се даправи поръчка, кодът се изпълнява. Това често сумарно се изразява с думите “изпращане на съобщение” (поръчка) към обект и обектът прави необходимото (изпълнява код).
Във всяко взаимоотношение е важно е да има граници, които се уважават от всички страни. Когато създавате библиотеки вие установявате взаимоотношения с клиентите, които са други програмисти, идползуващи вашата библиотека за създаване на програми или по-големи библиотеки.
Ако всички членове на клас са достъпни за всеки, клиентите биха могли да правят всичко с тях и няма начин да се наложи някакво определено поведение в тази дейност. Даже и да не искате клиентите да променят някои неща, не може да го предотвратите.
Има две причини да се контролира досъпа до членовете на клас. Първата е да се предотврати намесата на клиентите във вътрешните механизми на работа на класа и други важни части, които не засягат приложението на класа от гледна точка на приложение на интерфейса му. Това на практика е услуга за потребителите, понеже те не могат да знаят кое е важно да не се пипа и кое може да се променя.
Втората причина е разработчикът на библиотеката да може да я променя без да мисли за това как промяната ще се отрази на други програми. Например може да решите да направите някакъв клас за да улесните писането на реализация, а после да решите да го пренапишете, за да се изпълнява по-бързо. Ако интерфейсът и реализацията са внимателно разделени и скрити това може да се направи и от клиента ще се иска само ново свързване на неговите програми.
Java използва три явни ключови думи и една подразбираща се за установяване на необходимото: public, private, protected и подразбиращата се “приятелски,” която е в сила, ако не посочите някоя от другите. Тяхната употреба и значение са забележително праволинейни. Тези спецификатори на достъпа определят кой може да използва следващата ги дефиниция. public означава, че нещото е достъпно за всеки. private от друга страна, означава че всичко е недостъпно освен за вас, създателя на класа. private е тухлена стена между вас и програмистът-клиент. Ако някой опита достъп до такъв член, получава грешка по време на компилацията. “приятелски” работи с нещо, наречено “package,” начинът за правене на библиотеки в Java. Ако нещо е “приятелско”, то е достъпно само в рамките на package. (Затова това ниво на достъп е известно като “package access”). protected е също като private с това изключение, че наследяващия клас има достъп до protected членовете но не и до private членовете.
Сподели с приятели: |