Różnica między spójnością a sprzężeniem


486

Jaka jest różnica między spójnością a sprzężeniem?

W jaki sposób sprzężenie i spójność mogą prowadzić do dobrego lub złego projektu oprogramowania?

Jakie są przykłady ilustrujące różnicę między nimi i ich wpływ na ogólną jakość kodu?



3
Chciałbym zwrócić uwagę na ten artykuł: Rozwój oprogramowania SOLID, krok po kroku . Grz, Kris.
Kris van der Mast

4
To jest najnowszy post na ten temat
Janisz

Odpowiedzi:


702

Spójność odnosi się do tego, co może zrobić klasa (lub moduł). Niska spójność oznaczałaby, że klasa wykonuje różnorodne działania - jest szeroka, nie koncentruje się na tym, co powinna zrobić. Wysoka spójność oznacza, że ​​klasa koncentruje się na tym, co powinna robić, tj. Tylko na metodach związanych z intencją klasy.

Przykład niskiej spójności:

-------------------
| Staff           |
-------------------
| checkEmail()    |
| sendEmail()     |
| emailValidate() |
| PrintLetter()   |
-------------------

Przykład wysokiej spójności:

----------------------------
| Staff                   |
----------------------------
| -salary                 |
| -emailAddr              |
----------------------------
| setSalary(newSalary)    |
| getSalary()             |
| setEmailAddr(newEmail)  |
| getEmailAddr()          |
----------------------------

Jeśli chodzi o sprzężenie , odnosi się do tego, jak powiązane lub zależne są dwie klasy / moduły względem siebie. W przypadku klas o niskim sprzężeniu zmiana czegoś ważnego w jednej klasie nie powinna wpływać na drugą. Wysokie sprzężenie utrudniłoby zmianę i utrzymanie kodu; ponieważ klasy są ze sobą ściśle powiązane, dokonanie zmiany może wymagać przebudowy całego systemu.

Dobry projekt oprogramowania ma wysoką spójność i niskie sprzężenie .


12
Nie widzę, jak usunięcie kilku metod i dodanie kilku innych zwiększa spójność. Czy ktoś może tu pomóc?
Saket Jain

3
@SaketJain to nie tylko usuwanie niektórych metod i dodawanie innych. to w jaki sposób metody są powiązane z celem klasy (jeśli to wyjaśnienie jest jaśniejsze).
mauris

4
przykład niskiej kohezji u góry wygląda całkiem dobrze, myślę, że przypadkowo chciałeś powiedzieć „wysoka kohezja”
powtórz

37
@SaketJain Klasa Staff nie jest miejscem, w którym sprawdzamy, wysyłamy lub sprawdzamy wiadomości e-mail. Funkcje te powinny wchodzić w hipotetyczną klasę e-mail, dlatego jest to niska spójność. W drugim przykładzie klasa Staff zawiera tylko odpowiednie informacje do ustawiania i uzyskiwania danych związanych z Staff. Nie wykonują działań, którymi powinna zarządzać inna klasa.
Antonio Pantano

3
@JonathanC przykłady nie muszą dowodzić różnicy (jak w matematyce), aby nadal być przykładem. Zachęcamy do odpowiedzi lub komentowania wszelkich przykładów, które uważasz za bardziej pomocne. Funkcje set& getilustrują funkcjonalność, która jest bardziej specyficzna dla kontekstu „Staff” - im wyższa specyficzność, tym przykład daje większą spójność.
cellepo

81

Spójność jest wskaźnikiem zależności w module.

Sprzężenie jest wskaźnikiem zależności między modułami.

wprowadź opis zdjęcia tutaj

Spójność

  • Spójność jest wskaźnikiem zależności w module.
  • Kohezja pokazuje względną wytrzymałość funkcjonalną modułu.
  • Spójność to stopień (jakość), w jakim komponent / moduł koncentruje się na jednej rzeczy.
  • Podczas projektowania powinieneś dążyć do wysokiej spójności, tj. Spójnego komponentu / modułu skupiającego się na jednym zadaniu (tj. Jednomyślności) przy niewielkiej interakcji z innymi modułami systemu.
  • Spójność jest rodzajem naturalnego rozszerzenia ukrywania danych, na przykład klasa, w której wszyscy członkowie są widoczni, a pakiet ma domyślną widoczność. Spójność jest koncepcją wewnętrzną modułu.

Sprzęganie

  • Sprzężenie jest wskaźnikiem zależności między modułami.
  • Sprzężenie pokazuje względną zależność / współzależność między modułami.
  • Sprzężenie to stopień, w jakim komponent / moduł jest połączony z innymi modułami.
  • Podczas projektowania należy dążyć do niskiego sprzężenia, tzn. Zależność między modułami powinna być mniejsza
  • Tworzenie prywatnych pól, metod prywatnych i klas niepublicznych zapewnia luźne połączenie.
  • Sprzęganie jest koncepcją między modułami.

sprawdź ten link


77

Wysoka spójność w modułach i niskie połączenie między modułami są często uważane za związane z wysoką jakością w językach programowania OO.

Na przykład kod w każdej klasie Java musi mieć wysoką spójność wewnętrzną, ale być możliwie luźno powiązany z kodem w innych klasach Java.

Świetny opis tych problemów zawiera rozdział 3 Meyer Object-Oriented Software Construction (2. edycja) .


3
Pojęcia tak naprawdę nie są ograniczone do programowania OO. Jeśli cokolwiek, sugerowałbym, że celem języków OO jest poprowadzenie programisty do celów wysokiej kohezji / niskiego sprzężenia.
Hutch

57

Spójność wskazuje, w jaki sposób powiązane i skoncentrowane są obowiązki elementu oprogramowania.

Sprzęganie odnosi się do tego, jak silnie element oprogramowania jest połączony z innymi elementami.

Elementem oprogramowania może być klasa, pakiet, komponent, podsystem lub system. Podczas projektowania systemów zalecane jest posiadanie elementów oprogramowania, które mają wysoką kohezję i obsługują niskie sprzężenie .

Niska kohezja powoduje, że klasy monolityczne są trudne do utrzymania, zrozumienia i zmniejszają możliwość ponownego użycia. Podobnie wysokie sprzężenie powoduje, że klasy są ściśle powiązane, a zmiany nie są nielokalne, trudne do zmiany i zmniejszają ponowne użycie.

Możemy przyjąć hipotetyczny scenariusz, w którym projektujemy typowy monitor ConnectionPoolz następującymi wymaganiami. Zauważ, że może to zbytnio wyglądać jak na prostą klasę, ConnectionPoolale podstawowym celem jest tylko wykazanie niskiego sprzężenia i wysokiej kohezji za pomocą prostego przykładu i myślę, że powinien pomóc.

  1. wsparcie w uzyskaniu połączenia
  2. zwolnić połączenie
  3. uzyskać statystyki dotyczące liczby połączeń i wykorzystania
  4. uzyskać statystyki dotyczące połączenia w funkcji czasu
  5. Przechowuj informacje o pobieraniu i uwalnianiu połączenia w bazie danych w celu późniejszego zgłoszenia.

Przy niskiej spójności moglibyśmy zaprojektować ConnectionPoolklasę, silnie upychając wszystkie te funkcje / obowiązki w jedną klasę, jak poniżej. Widzimy, że ta pojedyncza klasa jest odpowiedzialna za zarządzanie połączeniami, interakcję z bazą danych oraz utrzymywanie statystyk połączeń.

Pula połączeń o niskiej kohezji

Dzięki wysokiej spójności możemy przypisać tę odpowiedzialność między klasami i uczynić ją łatwiejszą do utrzymania i wielokrotnego użytku.

Pula połączeń o wysokiej kohezji

Aby zademonstrować niskie sprzężenie , będziemy kontynuować ConnectionPoolpowyższy schemat wysokiej kohezji . Jeśli spojrzymy na powyższy schemat, chociaż obsługuje on wysoką spójność, ConnectionPooljest ściśle powiązany z ConnectionStatisticsklasą i PersistentStoreoddziałuje z nimi bezpośrednio. Zamiast tego, aby zmniejszyć sprzężenie, moglibyśmy wprowadzić ConnectionListenerinterfejs i pozwolić tym dwóm klasom zaimplementować interfejs i pozwolić im zarejestrować się w ConnectionPoolklasie. I ConnectionPoolbędą iterować przez tych słuchaczy i powiadamiać ich o zdarzeniach związanych z uzyskiwaniem i zwalnianiem połączenia, co pozwoli na mniej sprzężenia.

Niskie połączenie sprzęgające Pula

Uwaga / słowo lub przestroga: w tym prostym scenariuszu może to wyglądać na przesadę, ale jeśli wyobrażamy sobie scenariusz w czasie rzeczywistym, w którym nasza aplikacja musi wchodzić w interakcje z wieloma usługami stron trzecich, aby sfinalizować transakcję: Bezpośrednie połączenie naszego kodu z usługami strony trzeciej oznaczałoby to, że wszelkie zmiany w usłudze strony trzeciej mogą spowodować zmiany w naszym kodzie w wielu miejscach, zamiast tego możemy mieć wewnętrzną Facadeinterakcję z tymi wieloma usługami, a wszelkie zmiany w usługach stają się lokalne Facadei wymuszają niskie powiązania z osobą trzecią usługi.


3
Doskonała odpowiedź! Jeśli to możliwe, czy możesz użyć innego przykładu? Pula połączeń może nie być dla wszystkich jasna. Niezależnie od tego naprawdę mi pomogło. Więc dziękuję!
Saket Jain

W jaki sposób użycie interfejsu ConnectionListener pomaga zredukować sprzężenie? Czy możesz podać przykład, który jest łatwiejszy do zrozumienia?
abhishek gupta

1
@abhishekgupta W tym przykładzie mogłeś zauważyć, że użyliśmy wzorca obserwatora, aby uzyskać niskie / luźne sprzężenie. Przejście tego pomogłoby W jaki sposób Observer tworzy luźno powiązane projekty?
Madhusudana Reddy Sunnapu

33

Zwiększona spójność i zmniejszone sprzężenie prowadzą do dobrego projektowania oprogramowania.

Spójność dzieli twoją funkcjonalność tak, aby była zwięzła i zbliżona do istotnych dla niej danych, a oddzielenie zapewnia, że ​​funkcjonalna implementacja jest odizolowana od reszty systemu.

Oddzielenie pozwala zmienić implementację bez wpływu na inne części oprogramowania.

Spójność zapewnia, że ​​wdrożenie bardziej specyficzne dla funkcjonalności, a jednocześnie łatwiejsze w utrzymaniu.

Najbardziej skuteczną metodą zmniejszania sprzężenia i zwiększania spójności jest projektowanie według interfejsu .

To główne obiekty funkcjonalne powinny się „znać” tylko za pośrednictwem interfejsu (interfejsów), które implementują. Wdrożenie interfejsu wprowadza spójność jako naturalną konsekwencję.

Choć w niektórych senariach nie jest to realistyczne, powinno być celem projektu.

Przykład (bardzo szkicowy):

public interface IStackoverFlowQuestion
      void SetAnswered(IUserProfile user);
      void VoteUp(IUserProfile user);
      void VoteDown(IUserProfile user);
}

public class NormalQuestion implements IStackoverflowQuestion {
      protected Integer vote_ = new Integer(0);
      protected IUserProfile user_ = null;
      protected IUserProfile answered_ = null;

      public void VoteUp(IUserProfile user) {
           vote_++;
           // code to ... add to user profile
      }

      public void VoteDown(IUserProfile user) {
          decrement and update profile
      }

      public SetAnswered(IUserProfile answer) {
           answered_ = answer
           // update u
      }
}

public class CommunityWikiQuestion implements IStackoverflowQuestion {
     public void VoteUp(IUserProfile user) { // do not update profile }
     public void VoteDown(IUserProfile user) { // do not update profile }
     public void SetAnswered(IUserProfile user) { // do not update profile }
}

W niektórych innych miejscach w bazie kodu możesz mieć moduł przetwarzający pytania niezależnie od tego, czym one są:

public class OtherModuleProcessor {
    public void Process(List<IStackoverflowQuestion> questions) {
       ... process each question.
    }
}

28

najlepsze wyjaśnienie kohezji pochodzi z czystego kodu wuja Boba:

Klasy powinny mieć niewielką liczbę zmiennych instancji. Każda z metod klasy powinna manipulować jedną lub większą liczbą tych zmiennych. Zasadniczo im więcej zmiennych manipuluje metoda, tym bardziej spójna jest jej metoda . Klasa, w której każda zmienna jest używana przez każdą metodę, jest maksymalnie spójna.

Zasadniczo nie jest ani wskazane, ani możliwe tworzenie takich maksymalnie spójnych klas; z drugiej strony chcielibyśmy, aby spójność była wysoka . Gdy spójność jest wysoka, oznacza to, że metody i zmienne klasy są współzależne i łączą się razem jako logiczna całość.

Strategia utrzymywania małych funkcji i krótkich list parametrów może czasami prowadzić do mnożenia zmiennych instancji, które są używane przez podzbiór metod. Kiedy tak się dzieje, prawie zawsze oznacza to, że przynajmniej jedna inna klasa próbuje wydostać się z większej klasy. Powinieneś spróbować podzielić zmienne i metody na dwie lub więcej klas, tak aby nowe klasy były bardziej spójne.


Zgadzam się, że jest to prawdopodobnie najlepsze wytłumaczenie, to właśnie podoba mi się wuja Boba, że ​​może wyjaśnić rzeczywiste znaczenie w kilku zdaniach. Znając tę ​​definicję, możesz od razu zobaczyć, co należy zrobić danej klasie, aby zwiększyć jej spójność.
Paweł Dubiel,

13

po prostu spójność reprezentuje stopień, w jakim część podstawy kodu tworzy logicznie pojedynczą jednostkę atomową. Z drugiej strony sprzężenie reprezentuje stopień, w jakim pojedyncza jednostka jest niezależna od innych. Innymi słowy, jest to liczba połączeń między dwiema lub więcej jednostkami. Im mniejsza liczba, tym niższe sprzęgło.

Zasadniczo wysoka spójność oznacza utrzymywanie części bazy kodu, które są ze sobą powiązane w jednym miejscu. Jednocześnie niskie sprzężenie polega na jak największym oddzieleniu niepowiązanych części podstawy kodu.

Rodzaje kodu z perspektywy spójności i sprzężenia:

Idealny jest kod zgodny z wytycznymi. Jest luźno sprzężony i bardzo spójny. Możemy zilustrować taki kod za pomocą tego obrazu:wprowadź opis zdjęcia tutaj

Boski Obiekt jest wynikiem wprowadzenia wysokiej kohezji i wysokiego sprzężenia. Jest to anty-wzorzec i zasadniczo oznacza pojedynczy fragment kodu, który wykonuje całą pracę na raz: źle wybrany ma miejsce, gdy granice między różnymi klasami lub modułami są źle wybranewprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

Niszczycielskie odsprzęganie jest najbardziej interesujące. Czasami zdarza się, gdy programista próbuje rozdzielić bazę kodu tak bardzo, że kod całkowicie traci koncentrację:wprowadź opis zdjęcia tutaj

czytaj więcej tutaj


1
Doskonały artykuł i ilustracje! Jeśli mogę zasugerować ulepszenie choćby jednej myśli, podoba mi się, jak „źle wybrany” utrzymuje grupy komponentów o niepowiązanej semantyce w małych rojach, ale myślę, że powinny mieć między nimi wyraźnie więcej strzał. W końcu nawet na wykresach 4-kwadratowych jest to ten, który mieści się w górnym zakresie osi „Sprzężenia”.
Sławomir Brzeziński

1
Powiedziałbym również, że „źle wybrany” powinien mieć mniej strzał w każdym roju. Korzystając z przykładu „struktury folderów” z twojego artykułu, który klasyfikujesz jako „źle wybrane” repozytoria lub fabryki z pewnością nie będą ze sobą rozmawiać.
Sławomir Brzeziński

AKTUALIZACJA: Podniosłem te sugestie do pierwotnego autora obrazu i autor się z nimi zgodził .
Sławomir Brzeziński

11

Spójność w inżynierii oprogramowania to stopień, w jakim elementy danego modułu należą do siebie. Jest to zatem miara tego, jak silnie powiązany jest każdy element funkcjonalności wyrażony przez kod źródłowy modułu oprogramowania.

Łącząc w prostych słowach, jest to, ile jeden składnik (ponownie, wyobraź sobie klasę, choć niekoniecznie) wie o wewnętrznych działaniach lub wewnętrznych elementach innego, tj. Ile ma wiedzy na temat drugiego elementu.

Napisałem o tym post na blogu , jeśli chcesz przeczytać trochę więcej szczegółów z przykładami i rysunkami. Myślę, że to odpowiada na większość twoich pytań.


4

wprowadź opis zdjęcia tutaj

spójność odnosi się do tego, jak zaprojektowano jedną klasę. Spójność jest zasadą obiektową, ściśle związaną z zapewnieniem, że klasa została zaprojektowana w jednym, dobrze ukierunkowanym celu. Im bardziej skoncentrowana jest klasa, tym bardziej jej spójność jest większa. Zaletą wysokiej spójności jest to, że takie klasy są znacznie łatwiejsze do utrzymania (i rzadziej zmieniane) niż klasy o niskiej spójności. Inną zaletą wysokiej spójności jest to, że klasy o dobrze ukierunkowanym celu są zwykle bardziej użyteczne niż inne klasy.

Na powyższym zdjęciu widać, że przy niskiej spójności tylko jedna klasa jest odpowiedzialna za wykonanie wielu zadań, które nie są wspólne, co zmniejsza szansę na ponowne użycie i utrzymanie. Ale w wysokiej spójności istnieje osobna klasa dla wszystkich zadań do wykonania określonego zadania, co skutkuje lepszą użytecznością i konserwacją.


2

Kohezja (kohezja): Co, co oznacza razem , hesion, która oznacza trzymać się . System sklejania się cząstek różnych substancji.

Na przykład z życia: img Dzięki uprzejmości
wprowadź opis zdjęcia tutaj

Całość jest większa niż suma części - Arystoteles.

  • Kohezja jest porządkowym typem pomiaru i jest zwykle opisywana jako „wysoka kohezja” lub „niska kohezja”. Moduły o wysokiej kohezji są zwykle preferowane, ponieważ wysoka kohezja jest związana z kilkoma pożądanymi cechami oprogramowania, w tym odpornością, niezawodnością, możliwością ponownego użycia i zrozumiałością. Natomiast niska kohezja wiąże się z niepożądanymi cechami, takimi jak trudności w utrzymaniu, testowaniu, ponownym użyciu, a nawet zrozumieniu. wiki

  • Sprzężenie zwykle kontrastuje ze spójnością . Niskie sprzężenie często koreluje z wysoką kohezją i odwrotnie. Niskie sprzężenie jest często oznaką dobrze skonstruowanego systemu komputerowego i dobrego projektu, a w połączeniu z wysoką spójnością wspiera ogólne cele wysokiej czytelności i łatwości konserwacji. wiki


1

Myślę, że różnice można przedstawić następująco:

  • Kohezja reprezentuje stopień, w jakim część podstawy kodu tworzy logicznie pojedynczą jednostkę atomową.
  • Sprzężenie reprezentuje stopień, w jakim pojedyncza jednostka jest niezależna od innych.
  • Niemożliwe jest zarchiwizowanie pełnego oddzielenia płatności bez szkody dla spójności i odwrotnie.

W tym poście na blogu piszę o tym bardziej szczegółowo.


1

Spójność wskazuje na względną wytrzymałość funkcjonalną modułu.

  • Spójny moduł wykonuje jedno zadanie, wymagające niewielkiej interakcji z innymi komponentami w innych częściach programu. Mówiąc prosto, spójny moduł powinien (najlepiej) zrobić tylko jedną rzecz.
  • View Konwencjonalny widok:

    „jednomyślność” modułu

  • Widok OO:

    Hesion spójność oznacza, że ​​komponent lub klasa obejmuje tylko atrybuty i operacje, które są ściśle ze sobą powiązane oraz z klasą lub samym komponentem

  • Evel Poziomy spójności

     Funkcjonalny

    Ay Warstwa

    Komunikacyjny

    EquSequential

    Roc Procedura

    Em Czasowy

    Ilityutility

Sprzężenie jest wskaźnikiem względnej współzależności między modułami.

  • Sprzężenie zależy od złożoności interfejsu między modułami, momentu wprowadzenia lub odwołania do modułu i tego, jakie dane przechodzą przez interfejs.

  • Widok konwencjonalny: stopień, w jakim komponent jest połączony z innymi komponentami i światem zewnętrznym

  • Widok OO: jakościowa miara stopnia, w jakim klasy są ze sobą połączone

  • Poziom sprzężenia

     Treść

    Omm Często

     Kontrola

    AmpStamp

    Dane

    CallPonowne połączenie

    Use Wpisz typ

    CWłączenie lub import

     Zewnętrzny #


1

Sprzężenie = interakcja / relacja między dwoma modułami ... Spójność = interakcja między dwoma elementami w module.

Oprogramowanie składa się z wielu modułów. Moduł składa się z elementów. Weź pod uwagę, że moduł to program. Funkcja w programie jest elementem.

W czasie wykonywania dane wyjściowe programu są wykorzystywane jako dane wejściowe dla innego programu. Nazywa się to interakcją między modułami lub komunikacją między procesami. Jest to również nazywane sprzężeniem.

W ramach jednego programu dane wyjściowe funkcji są przekazywane do innej funkcji. Nazywa się to interakcją elementów w module. Nazywa się to również Spójnością.

Przykład:

Łączenie = komunikacja między 2 różnymi rodzinami ... Spójność = komunikacja między ojcem-matką-dzieckiem w rodzinie.


1
Jak więc wyjaśnić je w kontekście ich wpływu na oprogramowanie?
Itban Saeed,

Oprogramowanie składa się z wielu modułów. Moduł składa się z elementów. Weź pod uwagę, że moduł to program. Funkcja w programie jest elementem.
Dipankar Nalui,

1

Mówiąc najprościej, spójność oznacza, że ​​klasa powinna reprezentować jedną koncepcję.

Publiczny interfejs klasy jest spójny, jeśli wszystkie funkcje klasy są powiązane z koncepcją reprezentowaną przez klasę. Na przykład, zamiast posiadania klasy CashRegister, posiadanie funkcji CashRegister i Monety powoduje, że spójność dzieli ją na 2 klasy - klasę CashRegister i Monet.

W sprzężeniu jedna klasa zależy od drugiej, ponieważ wykorzystuje obiekty klasy.

Problem z wysokim sprzężeniem polega na tym, że może powodować działania niepożądane. Jedna zmiana w jednej klasie może spowodować nieoczekiwany błąd w drugiej klasie i może uszkodzić cały kod.

Ogólnie wysoką kohezję i niskie sprzężenie uważa się za OOP wysokiej jakości.


0

Termin „ spójność” jest rzeczywiście nieco sprzeczny z intuicją w odniesieniu do tego, co oznacza w projektowaniu oprogramowania.

Wspólnym znaczeniem kohezji jest to, że coś, co dobrze do siebie pasuje, jest zjednoczone, które charakteryzuje się silnym wiązaniem, takim jak przyciąganie molekularne. Jednak w projektowaniu oprogramowania oznacza to dążenie do klasy, która idealnie robi tylko jedną rzecz, więc wiele podmodułów nawet nie jest zaangażowanych.

Być może możemy myśleć o tym w ten sposób. Część ma największą spójność, gdy jest jedyną częścią (robi tylko jedną rzecz i nie można jej dalej rozbić). Jest to pożądane w projektowaniu oprogramowania. Spójność to po prostu inna nazwa „pojedynczej odpowiedzialności” lub „rozdzielenia obaw”.

Pojęcie sprzężenia na ręce jest dość intuicyjne, co oznacza, że ​​moduł nie zależy od zbyt wielu innych modułów, a te, z którymi się łączy, można łatwo zastąpić, na przykład przestrzegając zasady podstawienia Liskova .


Dlaczego ludzie nadal używają słowa moduł zamiast klasy?
northerner

1
@northerner to po prostu bardziej ogólny termin.
zar

0

Różnica teorii

Spójność

  • Spójność wskazuje na względną wytrzymałość funkcjonalną modułu.
  • Spójny moduł wykonuje jedno zadanie, wymagające niewielkiej interakcji z innymi komponentami w innych częściach programu.
  • Mówi się, że moduł o wysokiej kohezji i niskim sprzężeniu jest funkcjonalnie niezależny od innych modułów.

Klasyfikacja spójności

1. Przypadkowy 2. Logiczny 3. Czasowy 4. Procedura 5. Komunikacja 6. Odpowiedni 7. Funkcjonalny

Sprzęganie

  • Sprzężenie jest wskaźnikiem względnej współzależności między modułami.
  • Stopień sprzężenia między dwoma modułami zależy od ich złożoności interfejsu.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.