Fandom

Education

PWr - Programowanie obiektowe

429pages on
this wiki
Add New Page
Talk0 Share

Programowanie obiektowe (ang. object-oriented programming) to metodologia tworzenia programów komputerowych, która definiuje programy za pomocą "obiektów" - elementów łączących stan (czyli dane) i zachowanie (czyli procedury, tu: metody). Obiektowy program komputerowy wyrażony jest jako zbiór takich obiektów, komunikujących się pomiędzy sobą w celu wykonywania zadań. Podejście to różni się od tradycyjnego programowania proceduralnego, gdzie dane i procedury nie są ze sobą bezpośrednio związane. Programowanie obiektowe ma ułatwić pisanie, konserwację i wielokrotne użycie programów lub ich fragmentów.


== Programowanie obiektowe a rzeczywistość==


Największym atutem programowania, projektowania oraz analizy obiektowej jest zgodność takiego podejścia z rzeczywistością - mózg ludzki jest w naturalny sposób najlepiej przystosowany do takiego podejścia przy przetwarzaniu informacji. Już Arystoteles analizując rzeczywistość wprowadził pojęcia formy (odpowiednika platońskiej idei) i materii. Formie w programowaniu obiektowym odpowiada Klasa, materii - instancja - obiekt. Jest to najbardziej naturalny sposób rozumienia rzeczywistości - podstawową cechą mózgu ludzkiego jest klasyfikacja - łączenie występujących w rzeczywistości obiektów w grupy - klasy. Odbywa się to na podstawie wspólnych cech dla grup obiektów - w tym podobnych zachowań. Od urodzenia cały świat jawi się nam jako zbiór obiektów, które wchodzą ze sobą w interakcje. Obiekty te w trakcie poznawania coraz większej ich ilości grupujemy w klasy. Korzystając z podejścia obiektowego przy programowaniu korzystamy w najlepszy sposób z właściwości naszego mózgu - jesteśmy w stanie panować nad większymi strukturami, niż przy innych - mniej naturalnych podejściach. Jeżeli działający program ma być pewnym tworem przetwarzającym informację - pewnym modelem rzeczywistości - to im bardziej ten twór będzie naśladował rzeczywistość, w której żyjemy - tym lepiej będzie z nią współpracował (tym bardziej będzie zrozumiały). Jest to zgodne z teorią, która mówi, że tym lepszy jest model, im bardziej jest zgodny z rzeczywistością.


== Podstawowe założenia paradygmatu obiektowego==


Istnieje pewna różnica zdań co do tego, jakie cechy metody czy języka programowania czynią je "orientowanymi obiektowo", jednak powszechnie uważa się, że najważniejsze są następujące cechy:


=Edit

Abstrakcja===


Skrót: Każdy obiekt w systemie służy jako model abstrakcyjnego "wykonawcy", który może wykonywać pracę, opisywać i zmieniać swój stan, oraz komunikować się z innymi obiektami w systemie, bez ujawniania, w jaki sposób zaimplementowano dane cechy. Procesy, funkcje lub metody mogą być również abstrahowane, a kiedy tak się dzieje, konieczne są rozmaite techniki rozszerzania abstrakcji.


Rozwinięcie: Abstrakcją w programowaniu nazywamy pewnego rodzaju uproszczenie rozpatrywanego problemu, polegające na ograniczeniu zakresu cech manipulowanych obiektów wyłącznie do cech kluczowych dla algorytmu, a jednocześnie niezależnych od implementacji. W tym sensie abstrakcja jest odmianą formalizmu matematycznego. Cel stosowania abstrakcji jest dwojaki: ułatwienie rozwiązania problemu i zwiększenie jego ogólności.


Języki programowania mogą oferować specjalne narzędzia do tworzenia pewnych typów abstrakcji, jednak pojęcie to nie zależy w żaden sposób od konkretnego języka. Każde uogólnienie problemu mające na celu wyizolowanie jego kluczowych aspektów jest abstrakcją.


Dla przykładu, dany program może przetwarzać różne zbiory obiektów, jednak wszystkie one mają wspólną cechę - w pewnych warunkach można je traktować jako listę o następujących operacjach: pierwszy(), ostatni() i następny() oraz predykacie czy_ostatni(). Dlatego dla potrzeb fragmentów zajmujących się przetwarzaniem list, wygodnie jest wprowadzić abstrakcję iteratora, który będzie udostępniał te właśnie operacje. W języku Java deklaracja interfejsu realizującego tę abstrakcję mogłaby wyglądać następująco:


public interface IterListy 
{
    public void pierwszy();
    public void ostatni();
    public void następny();
    public boolean czy_ostatni();
}

// ...

public void przetwarzaj_listę(IterListy iter_listy)
{
    while (! iter_listy.czy_ostatni())
    {
        // zrób coś
        iter_listy.następny();
    }
}


Dla porówniania, w języku Python żadna formalna deklaracja nie jest potrzebna, kod przetwarzający listy po prostu odwołuje się do odpowiednich metod obiektu:


def przetwarzaj_listę(iter_listy):
    while not iter_listy.czy_ostatni():
        # zrób coś
        iter_listy.następny()


W rzeczywistości, w Pythonie abstrakcja iteratora jest wbudowana w język, wobec czego powyższy fragment można przepisać jako:

def przetwarzaj_listę(lista):
   for obiekt in lista:
      # zrób coś


Pętla for użyta w tym fragmencie doskonale ilustruje użyteczność abstrakcji - ponieważ całkowicie pomijamy jakiekolwiek charakterystyczne cechy przetwarzanych kolekcji obiektów, for może z równym powodzeniem obsługiwać każdą z nich, pod warunkiem jedynie że dany typ implementuje odpowiedni zbiór operacji. Dzięki temu for stosować można do list, słowników, krotek, zbiorów itd. Jednocześnie unikamy angażowania się w szczegóły implementacji nieistotne dla rozwiązywanego problemu, tj. przeglądania kolekcji obiektów.


==Edit

Inne użycia====


Termin abstrakcja bywa również używany w informatyce na określenie pokrewnej, jednak nie tożsamej techniki ukrywania implementacji za wspólnym interfejsem, który może korzystać z wielu różnych bibliotek do osiągnięcia pożądanej funkcjonalności. W tym sensie można mówić o abstrakcji bazy danych, mając na myśli kod który dostosowuje interfejs danej bazy danych do wspólnej postaci oczekiwanej przez program.


W praktyce, wiele popularnych bibliotek, w szczególności biblioteki standardowe i biblioteki ułatwiające pisanie przenośnych programów to biblioteki użytecznych abstrakcji, zarówno w pierwszym jak i drugim znaczeniu tego słowa.


=Edit

Enkapsulacja===


Skrót: Czyli ukrywanie implementacji, hermetyzacja. Zapewnia, że obiekt nie może zmieniać stanu wewnętrznego innych obiektów w nieoczekiwany sposób. Tylko wewnętrzne metody obiektu są uprawnione do zmiany jego stanu. Każdy typ obiektu prezentuje innym obiektom swój "interfejs", który określa dopuszczalne metody współpracy. Pewne języki osłabiają to założenie, dopuszczając pewien poziom bezpośredniego (kontrolowanego) dostępu do "wnętrzności" obiektu. Ograniczają w ten sposób poziom abstrakcji.


Rozwinięcie: Enkapsulacja to jedno z założeń paradygmatu programowania obiektowego. Polega ono na ukrywaniu pewnych danych składowych lub metod obiektów danej klasy tak, aby były one (i ich modyfikacja) dostępne tylko metodom wewnętrzynym danej klasy lub funkcjom z nią zaprzyjaźnionym. Z pełną enkapsulacją mamy do czynienia wtedy gdy dostęp do wszystkich pól w klasie jest możliwy tylko i wyłącznie poprzez metody, lub inaczej: gdy wszystkie pola w klasie znajdują się w sekcji prywatnej (lub chronionej).


==Edit

Przyczyny stosowania enkapsulacji:====


* Uodparnia tworzony model na błędy polegające np. na błędnym przypisywaniu wartości oraz umożliwia wykonanie czynności pomocniczych jak np. pobranie z konta 10% wypłacanej kwoty jako prowizja (nie uwidocznione w przykładzie).


Przykład:


typedef double TypPieniedzy;

class KontoBankowe {
  public:
    KontoBankowe( const TypPieniedzy saldoPoczatkowe = 0 ) throw();
    bool wplac( const TypPieniedzy kwota ) throw();
    bool wyplac( const TypPieniedzy kwota ) throw();
    TypPieniedzy podajStanKonta() const throw();
  private:
    TypPieniedzy saldo;
};

KontoBankowe::KontoBankowe( const TypPieniedzy saldoPoczatkowe = 0 ) throw()
  :
  saldo( saldoPoczatkowe )
  {
}
 bool KontoBankowe::wplac( const TypPieniedzy kwota ) throw()  {
  if ( kwota > 0 ) {
    saldo += kwota;
    return true;
  }
  return false;
}

bool KontoBankowe::wyplac( const TypPieniedzy kwota ) throw() {
  if ( ( kwota > 0 ) && ( kwota <= saldo ) ) {
      saldo -= kwota;
      return true;
  }
  return false;
}

TypPieniedzy KontoBankowe::podajStanKonta() const throw() {
  return saldo;
}


: Mamy klasę KontoBankowe. Nie powinno się tak zdarzyć, że stan konta mógłby być modyfikowany przez zwykłe odwołanie się do danej saldo (np.: mojeKonto.saldo = 123;). Tu saldo konta bankowego jest daną chronioną (dostęp jest private), do której dostęp mają tylko funkcje zaprzyjaźnione lub funkcje składowe (wewnętrzne) (tu: podajStanKonta, wplac i wyplac). Powinno się zapewnić maksymalne bezpieczeństwo w odniesieniu do danej saldo. Stąd też metoda TypPieniedzy podajStanKonta() jest oznaczona jako const, wartość kwoty w metodach void wplac( const TypPieniedzy kwota ) i void wyplac( const TypPieniedzy kwota ) jest określona również jako const aby jej wartość nie została "przypadkiem" zmieniona w trakcie działania tych metod. Enkapsulacja ma też na celu sprawdzanie poprawności wpisywanych danych (czy powinno się dać wpłacić na konto kwoty będącej wartością ujemną?).


* Lepiej oddaje rzeczywistość. W powyższym przykładzie obrazuje atomowe operacje na koncie bankowym, podczas gdy odwołanie się bezpośrednie do salda nie oznaczałoby nic szczególnego.


* Umożliwia rozbicie modelu na mniejsze elementy. Dzięki stosowaniu enkapsulacji można budować modele rzeczywistości jako struktury składające z mniejszych modułów, z których każdy ma pewne określone dane i określone metody wpływania na ich stan i sprawdzania go. Na przykład w tworzeniu modelu samochodu można użyć modułu silnika, który ma określony szereg danych wewnętrznych (np. opisujących jego stan w trakcie pracy) i metod wewnętrznych (np. pobranie paliwa, wywołanie reakcji, ruch wirnika). Wszystko to jednak jest nieistotne dla użytkownika (a nawet nie powinno być dostępne), który ma możliwość użycia tylko zapłonu i wyłączenia silnika.


=Edit

Polimorfizm===


Skrót: Referencje i kolekcje obiektów mogą dotyczyć obiektów różnego typu, a wywołanie metody dla referencji spowoduje zachowanie odpowiednie dla pełnego typu obiektu wywoływanego. Jeśli dzieje się to w czasie działania programu, to nazywa się to późnym wiązaniem lub wiązaniem dynamicznym. Niektóre języki udostępniają bardziej statyczne (w trakcie kompilacji) rozwiązania polimorfizmu - na przykład szablony i przeciążanie operatorów w C++.


=Edit

Dziedziczenie===


Skrót: Porządkuje i wspomaga polimorfizm i enkapsulację dzięki umożliwieniu definiowania i tworzenia specjalizowanych obiektów na podstawie bardziej ogólnych. Dla obiektów specjalizowanych nie trzeba redefiniować całej funkcjonalności, lecz tylko tę, której nie ma obiekt ogólniejszy. W typowym przypadku powstają grupy obiektów zwane klasami, oraz grupy klas zwane drzewami. Odzwierciedlają one wspólne cechy obiektów.


Rozwinięcie: Dziedziczenie (ang. inheritance) to w programowaniu obiektowym operacja polegająca na stworzeniu nowej klasy na bazie klasy już istniejącej.


Na przykład, jeśli mamy klasę (w C++):


class Punkt
{ 
public: 
   float x,y; 
   Punkt(float _x, float _y); 
   virtual void wypisz(); 
   virtual void przesuń(float przesuniecie_x, float przesuniecie_y); 
}; 


Załóżmy, że w naszym programie wynikła potrzeba użycia dodatkowej klasy, która różni się od tej jedynie w kilku szczegółach. Dzięki dziedziczeniu nie musimy tworzyć takiej klasy od zera, a możemy zamiast tego wprowadzić jedynie konieczne modyfikacje do klasy już istniejącej.


Przykładowo chcemy, by nowa klasa miała dodatkowy składnik:

string nazwa;


a także odpowiednio zmieniona metodę wypisz.


Dziedziczona klasa może zostać zdefiniowana w następujący sposób:

class NazwanyPunkt: public Punkt
{ 
public: 
   string nazwa;
   NazwanyPunkt(float _x=0,float _y=0,string _nazwa=NULL); 
   virtual void wypisz(); 
}; 


W ten sposób powstała nowa klasa o nazwie NazwanyPunkt (klasa pochodna, podklasa, potomek) wywodząca się od klasy Punkt (klasa podstawowa, nadklasa, rodzic).


Bardzo ważna w naszej klasie pochodnej jest pierwsza linijka:


class NazwanyPunkt: public Punkt


Wyrażenie znajdujące się po dwukropku nazywa się listą pochodzenia. W składni języka C++ informuje ona od czego wywodzi się klasa pochodna.


W C++ klasie pochodnej możemy zdefiniować:


* dodatkowe dane składowe (w naszym przykładzie: string nazwa;)

* dodatkowe funkcje składowe (w naszym przykładzie zmieniliśmy funkcję wypisz())

* nową treść funkcji wirtualnej


W innych językach szczegóły dziedziczenia mogą wyglądać odmiennie, np. w CLOS klasa pochodna może wpływać na metody odziedziczone po klasie podstawowej, ogólna zasada dziedziczenia pozostaje jednak taka sama.


==Edit

Dziedziczenie wielokrotne====


Dziedziczenie wielokrotne (ang. multiple inheritance) to operacja polegająca na dziedziczeniu po więcej niż jednej klasie bazowej. Dziedziczenie wielokrotne stosowane jest na przykład w języku C++. W innych językach programowania (np. w Javie) dopuszczalne jest wyłącznie dziedziczenie jednokrotne, zaś do uzyskania efektu, który w C++ osiąga się poprzez dziedziczenie wielokrotne używa się interfejsów.


Przeanalizujmy przykład (w C++):


class Samochod {
  public:
    int iloscKol;
    void jedz() { /* ciało metody */ }
};

class Lodz {
  public:
    float wypornosc;
    void plyn() { /* ciało metody */ }
};

class Amfibia : public Samochod , public Lodz {
  public:
    string nrRejestracyjny;
};


: W efekcie wielokrotnego dziedziczenia Klasa Amfibia posiada wszystkie pola i metody swoich klas bazowych.


Dzięki zastosowaniu wielokrotnego dziedziczenia, stworzony obiekt danej klasy jest wielotypowy. W odniesieniu do powyższczego przykładu możliwe są następujące operacje:


...
void napompujKolo( Samochod& samochod ) { /* ciało metody */ }
void naprawKadlub( Lodz& lodz ) { /* ciało metody */ }

int main() {
  Amfibia amfibia;
  napompujKolo( amfibia );
  naprawKadlub( amfibia );
  return 0;
}


: Widzimy, że obiekt amfibia jest jednocześnie typu Samochod i Lodz.


==Edit

Wielokrotne dziedziczenie a interfejsy====


Zarówno dziedziczenie wielokrotne, jak i interfejsy pozwalają na uzyskanie równoważnego efektu -- możliwości traktowania obiektu polimorficznie ze względu na wiele, niespokrewnionych ze sobą typów. Wielodziedziczenie jednakże jest techniką znacznie bardziej niebezpieczną, gdyż w przeciwieństwie do interfejsów, łączy w sobie środki do współdzielenia implementacji ze środkami współdzielenia zewnętrznego kontraktu klasy, a zatem dwie funkcje o radykalnie różnych zastosowaniach. Dlatego też użycie wielokrotnego dziedziczenia wymaga znacznej wiedzy o mechanizmach języka i ścisłej dyscypliny od stosującego je programisty, w przeciwnym wypadku bowiem istnieje niebezpieczeństwo stworzenia hierarchii klas w której zmiana szczegółów implementacyjnych może pociągnąć za sobą konieczność zmiany kontraktu, lub też sytuacji w której nie będzie możliwe stworzenie hierarchii o pożądanym kształcie bez wprowadzania nieprawidłowego zachowania obiektów.


Dla kontrastu, w przypadku użycia interfejsów, czynności dziedziczenia (współdzielenia implementacji) i dzielenia interfejsu (czyli zewnętrznego kontraktu) są celowo rozdzielone. W ten sposób nie jest możliwe przypadkowe pomylenie tych dwóch pojęć, co miałoby opłakane skutki.


Argumentem podnoszonym na rzecz wielokrotnego dziedziczenia bywa fakt, że umożliwia ono proste wykorzystanie istniejącej implementacji z więcej niż jednej klasy bazowej. Jest to prawda, jednak w rzeczywistości bardzo rzadko ten właśnie efekt jest tym co naprawdę ma zastosowanie w danej sytuacji, często zaś istnieje fałszywe wrażenie iż jest to potrzebne. Jeśli istotnie zachodzi potrzeba wykorzystania więcej niż jednej implementacji, w przypadku użycia interfejsów można wykorzystać techniki osadzania i delegacji; powoduje to konieczność większej pracy ze strony programisty, jednak zazwyczaj jest to pożądane, gdyż zmusza do głębszego zastanowienia się nad pomysłem łączenia niespokrewnionych klas, a dodatkowo powoduje, że nowa klasa zachowuje się dokładnie tak jak oczekuje tego programista, a nie tak jak stanowi definicja języka (która rzadko pokrywa się z intuicją w bardziej skomplikowanych obszarach, a wielodziedziczenie należy do najbardziej skomplikowanych).


Należy również pamiętać, że powyższe argumenty odnoszą się głównie do "tradycyjnych" języków o statycznym systemie typów, takich jak C++. W innych językach, takich jak Python, również istnieje mechanizm wielodziedziczenia, jednakże konstrukcja systemu typów i mechanizmu klas jest radykalnie odmienna, co powoduje że powyższa dyskusja traci swoją aktualność.


== Historia programowania obiektowego==


Koncepcja programowania obiektowego pierwotnie pojawiła się w Simuli 67, języku zaprojektowanym do zastosowań symulacyjnych, stworzonym przez Ole-Johana Dahla i Kristena Nygaarda z Norsk Regnesentral w Oslo. (Mówi się, że pracowali oni nad symulacjami zachowania się statków i mieli kłopoty z opanowaniem wszystkich zależności, jakie wywierały na siebie nawzajem wszystkie parametry statków w symulacji. Wtedy wpadli na pomysł, by pogrupować typy statków w różne klasy obiektów, a każda z klas sama odpowiadałaby za określanie własnych danych i zachowań.) Później koncepcja została dopracowana w języku Smalltalk, stworzonym w Simuli w Xerox PARC, ale zaprojektowanym jako w pełni dynamiczny system, w którym obiekty mogą być tworzone i modyfikowane "w locie", a nie system oparty na statycznych programach.


Programowanie obiektowe zyskało status techniki dominującej w połowie lat 80-tych, głównie ze względu na wpływ C++, stanowiącego rozszerzenie języka C. Dominacja C++ została utrwalona przez wzrost popularności graficznych interfejsów użytkownika, do tworzenia których programowanie obiektowe nadaje się szczególnie dobrze.


W tym okresie cechy obiektowe dodano do wielu języków programowania, w tym Ady, BASIC-a, Lisp-a, Pascala i innych. Dodanie obiektowości do języków, które pierwotnie nie były do niej przystosowane zrodziło szereg problemów z kompatybilnością i konserwacją kodu. Z kolei "czysto" obiektowym językom brakowało cech, z których programiści przyzwyczajeni byli korzystać. By zapełnić tę lukę podejmowano liczne próby stworzenia języków obiektowych dostarczających jednocześnie "bezpiecznych" elementów proceduralności. Eiffel Bertranda Meyera był wczesnym przykładem w miarę udanego języka spełniającego te założenia; obecnie został on w zasadzie całkowicie zastąpiony przez Javę, głównie za sprawą pojawienia się Internetu, dla którego Java dostarcza szeregu użytecznych funkcji.


Podobnie, jak programowanie funkcyjne doprowadziło do udoskonalenia technik takich, jak programowanie strukturalne, do współczesnych metod projektowania oprogramowania obiektowego zaliczają się takie usprawnienia, jak design patterns, design by contract i języki modelowania (np. UML).


Obiektowość rozprzestrzeniła się dość znacznie, jednak zwykle w systemach hybrydowych, w połączeniu z programowaniem niskopoziomowym (C++), funkcyjnym (Ruby, Ocaml, niektóre dialekty Lisp-a), sieciowym (Java), skryptowym (Perl, Python) itd. Systemy czysto obiektowe typu Smalltalk nie znalazły zbyt szerokiego zastosowania.


== Różne podejścia do realizacji paradygmatu==


Niektóre języki wprowadzają modyfikacje do założeń obiektowości, na przykład:


* w niektórych językach każda klasa musi mieć nadklasę

* w niektórych językach nadklas może być więcej niż jedna


== Elementarna charakterystyka cech popularnych języków programowania obiektowego==


Powyższa charakterystyka dopuszcza bardzo dużą różnorodność - i w rzeczywistości, o ile systemy programowania strukturalnego czy funkcyjnego były do siebie stostunkowo podobne, o tyle systemy obiektowe różnią się tak bardzo, że nie wiadomo co tak naprawdę znaczy nazwa obiektowe.


* Dziedziczenie wielokrotne:


** jest: C++, Python, Incr Tcl

** tylko interfejsy: Object Pascal, Java, C#

** tylko metody: Ruby

* Klasa jest obiektem:


** tak: Ruby, Python, Java (za pomocą obiektu Class)

** nie: C++, C#, Ocaml

* Wszystkie obiekty wywodzą się z jednego korzenia i muszą mieć nadklasę:


** tak: Java, C#, Ruby, Object Pascal, Incr Tcl, Python (klasy nowego typu)

** nie: C++, Ocaml, Python (klasy starego typu)

* Obiekt można pytać do której podklasy należy:


** tak: Ruby, C#, C++ (z RTTI), Java (RTTI lub mechanizm refleksji), Python, Object Pascal, Incr Tcl

** nie: Ocaml

* Mechanizm szablonów do automatycznego generowania klas (np. szablon Drzewo_Binarne<> z klasy X tworzy Drzewo_Binarne<X>):


** tak: Ruby, C++, Ocaml, C# 2.0

** nie: Java, (od wersji 1.5 wprowadzono mechanizm pozwalający uzyskać podobną funkcjonalność)

* Przeładowywanie (przeciążanie) operatorów:


** tak: Ruby, C++, Python, C#

** nie: Java (choć przeciążonych jest kilka operatorów wbudowanych, np. + w klasie String), Ocaml, Object Pascal (tak od BDS 2006)


== Klasy i obiekty==


Obiekt to podstawowe pojęcie wchodzące w skład paradygmatu obiektowości w analizie i projektowaniu oprogramowania oraz w programowaniu.


Obiekt ma budowę zbliżoną do struktury, jednak poza danymi zawiera także metody, czyli funkcje pozwalające na wykonanie na danych obiektu określonych zadań.


Z reguły obiekty (a właściwie klasy, do których te obiekty należą) są konstruowane tak, aby dane przez nie przenoszone były dostępne wyłącznie przez odpowiednie metody, co zabezpiecza je przed niepożądanymi modyfikacjami. Takie zamknięcie danych nazywa się enkapsulacją.


W istocie obiekty są rozwinięciem koncepcji programowania z kontrolą typów zmiennych. W programowaniu obiektowym obiekty tworzone są dynamicznie jako podstawowy element konstrukcji programu. Podobnie jak dla typu liczb naturalnych czy typu zmiennych znakowych, dla których zdefiniowane są pewne operacje jak np. dodawanie czy konkatenacja, a nie są zdefiniowane inne, jak np. operacje logiczne, tak dla obiektów programista decyduje o wykonalności pewnych operacji oraz definiuje ich funkcyjną postać. Użycie obiektów polega na ich zainicjalizowaniu (np. na nadaniu zmiennej całkowitej pewnej wartości np. 7) oraz na wykonywaniu na nich operacji zgodnie z definicją typu - obiektu.


Każdy obiekt ma trzy cechy:


* tożsamość, czyli cechę umożliwiającą jego identyfikację i odróżnienie od innych obiektów;

* stan, czyli aktualny stan danych składowych;

* zachowanie (ang. behaviour), czyli zestaw metod wykonujących operacje na tych danych.


Zapamiętaj: Klasa jest opisem pewnej koncepcji, obiekt to instancja tej klasy!


== Inne paradygmaty programowania==


* Programowanie proceduralne to paradygmat programowania zalecający dzielenie kodu na procedury, czyli fragmenty wykonujące ściśle określone operacje. Procedury nie powinny korzystać ze zmiennych globalnych (w miarę możliwości), lecz pobierać i przekazywać wszystkie dane (czy też wskaźniki do nich) jako parametry wywołania. Program proceduralny można opisać maszyną stanów.

* Programowanie strukturalne to paradygmat programowania zalecający hierarchiczne dzielenie kodu na moduły, które komunikują się jedynie poprzez dobrze określone interfejsy. Jest to rozszerzenie koncepcji programowania proceduralnego. Programowanie strukturalne stanowi dyscyplinę związaną z programowaniem proceduralnym, kładąc nacisk na stosowanie jednego tylko wyjścia z funkcji i rezygnację ze skoków (GOTO).

* Programowanie funkcyjne to filozofia programowania, w której funkcje należą do wartości podstawowych, a nacisk kładzie się na wartościowanie (często rekursywnych) funkcji, a nie na wykonywanie poleceń. Inaczej mówiąc: podstawowymi konstrukcjami języków funkcjonalnych są funkcje i ich wzajemne wywołania, nie dane (unika się koncepcji przechowywania danych w postaci zmiennych o pewnej wartości). Program funkcjonalny nie jest reprezentowany za pomocą maszyny stanów jak to się dzieje w przypadku programowania strukturalnego.


Pizdencja

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.