Kompozycja obiektu - Object composition

W informatyce , skład obiektu jest sposobem łączenia obiektów lub typów danych do bardziej złożonych. Typowymi rodzajami kompozycji są obiekty używane w programowaniu obiektowym , tagged unions , zestawy , sekwencje i różne struktury grafów . Kompozycje obiektów odnoszą się do struktur danych, ale nie są tym samym.

Kompozycja obiektu odnosi się do logicznej lub koncepcyjnej struktury informacji, a nie implementacji lub fizycznej struktury danych używanej do jej reprezentowania. Na przykład sekwencja różni się od zestawu tym, że (między innymi) kolejność komponowanych elementów ma znaczenie dla pierwszego, ale nie dla drugiego. Struktury danych, takie jak tablice , listy połączone , tablice mieszające i wiele innych, można wykorzystać do zaimplementowania każdego z nich. Być może mylące jest to, że niektóre z tych samych terminów są używane zarówno w odniesieniu do struktur danych, jak i kompozytów. Na przykład „ drzewo binarne ” może odnosić się do: jako struktury danych jest środkiem dostępu do liniowej sekwencji elementów, a rzeczywiste pozycje elementów w drzewie są nieistotne (drzewo może być wewnętrznie przeorganizowane w dowolny sposób, bez zmiany jego znaczenia). Jednak jako kompozycja obiektów pozycje są istotne, a ich zmiana zmieniłaby znaczenie (jak na przykład w kladogramach ).

Technika programowania

Programowanie obiektowe opiera się na obiektach, które hermetyzują dane i zachowanie. Wykorzystuje dwie główne techniki łączenia i komponowania funkcjonalności w bardziej złożone, podtypowanie i kompozycję obiektów. Kompozycja obiektów polega na łączeniu obiektów w obrębie obiektów złożonych, a jednocześnie zapewnia hermetyzację każdego obiektu za pomocą ich dobrze zdefiniowanego interfejsu bez widoczności ich elementów wewnętrznych. Pod tym względem kompozycja obiektów różni się od struktur danych, które nie wymuszają enkapsulacji.

Kompozycja obiektów może również dotyczyć grupy wielu powiązanych obiektów, takich jak zestaw lub sekwencja obiektów. Delegacja może wzbogacić kompozycję przez przekazywanie żądań lub wywołań wykonanych do otaczającego obiektu złożonego do jednego z jego wewnętrznych składników.

W klasowych i typizowanych językach programowania typy można podzielić na złożone i niezłożone, a kompozycję można traktować jako relację między typami: obiekt typu złożonego (np. samochód ) „ ma ” obiekty innych typów ( np. koło ). Gdy obiekt złożony zawiera kilka podobiektów tego samego typu, można im przypisać określone role , często rozróżniane według nazw lub numerów. Na przykład obiekt Point może zawierać 3 liczby, z których każda reprezentuje odległość wzdłuż innej osi, na przykład „x”, „y” i „z”. Generalnie badanie relacji część-całość to mereologia .

Kompozycję należy odróżnić od podtypów , czyli procesu dodawania szczegółów do ogólnego typu danych w celu utworzenia bardziej szczegółowego typu danych. Na przykład samochody mogą być określonym typem pojazdu: samochód to pojazd . Podtypowanie nie opisuje relacji między różnymi obiektami, ale mówi, że obiekty jednego typu są jednocześnie obiektami innego typu. Badanie takich relacji to ontologia .

W językach programowania opartych na prototypach , takich jak JavaScript , obiekty mogą dynamicznie dziedziczyć zachowania z obiektu prototypowego w momencie ich tworzenia. Kompozycję należy odróżnić od prototypowania: nowo utworzony obiekt dziedziczy kompozycję swojego prototypu, ale sam może być skomponowany samodzielnie.

Obiekty złożone mogą być reprezentowane w pamięci przez wspólne umiejscowienie złożonych obiektów, przez wspólne umiejscowienie referencji lub na wiele innych sposobów. Elementy w obiekcie złożonym mogą być określane jako atrybuty , pola , elementy członkowskie , właściwości lub inne nazwy , a wynikowa kompozycja jako typ złożony , rekord pamięci , struktura , krotka lub typ zdefiniowany przez użytkownika ( UDT ) . Aby uzyskać szczegółowe informacje, zapoznaj się z sekcją agregacji poniżej.

Technika modelowania UML

Klasa roweru reprezentowana w UML, z trzema właściwościami: siodełko, koła i części, przy czym dwie ostatnie mają wielokrotność wskazującą kilka obiektów
Kompozycja obiektów przy użyciu właściwości UML do komponowania obiektów

W modelowaniu UML obiekty mogą być komponowane koncepcyjnie, niezależnie od implementacji za pomocą języka programowania. Istnieją cztery sposoby tworzenia obiektów w UML: właściwość, asocjacja, agregacja i kompozycja:

  • Właściwość reprezentuje atrybut klasy.
  • Powiązanie reprezentuje semantyczną relację między instancjami skojarzonych klas. Koniec elementu członkowskiego asocjacji odpowiada właściwości skojarzonej klasy.
  • Agregacja jest rodzajem asocjacji, która modeluje relację część/całość pomiędzy agregatem (całością) a grupą powiązanych ze sobą komponentów (części).
  • Kompozycja, zwana także agregacją złożoną, jest rodzajem agregacji, która modeluje relację część/całość między kompozytem (całością) a grupą części, które są wyłączną własnością.

Relacja między agregatem a jego komponentami jest słabą relacją typu "ma-a": komponenty mogą być częścią kilku agregatów, mogą być dostępne przez inne obiekty bez przechodzenia przez agregat i mogą przetrwać obiekt agregatu. Stan obiektu składnika nadal stanowi część obiektu zagregowanego.

Związek między kompozycją a jego częściami jest silną relacją typu „ma-a”: obiekt złożony ponosi wyłączną „ odpowiedzialność za istnienie i przechowywanie złożonych obiektów ”, złożony obiekt może być częścią co najwyżej jednego złożonego, oraz „ Jeśli obiekt złożony zostanie usunięty, wszystkie jego wystąpienia części, które są obiektami, zostaną usunięte razem z nim ”. Tak więc w UML kompozycja ma węższe znaczenie niż zwykła kompozycja obiektów.

Powiązanie kilku rowerów, z których każdy ma jednego właściciela;  Skład roweru z częściami ramy, z których składa się rower;  i agregacja roweru z jego kołami, które istnieją bez roweru
Notacja UML dla asocjacji, składu i agregacji

Notacja graficzna przedstawia:

  • właściwość jako typowany element w polu otaczającej klasy,
  • skojarzenie jako prosta linia między skojarzonymi klasami,
  • agregacja jako niewypełniona diament na boku agregatu i linią ciągłą,
  • kompozycja jako wypełniony diament po stronie kompozytu i linia ciągła.


Formularze specjalne

Powstrzymywanie

Kompozycja używana do przechowywania kilku wystąpień złożonego typu danych jest określana jako zawieranie. Przykładami takich kontenerów są tablice , tablice asocjacyjne , drzewa binarne i listy połączone .

W UML zawieranie jest przedstawiane za pomocą wielokrotności 0..* lub 1..*, co wskazuje, że obiekt złożony składa się z nieznanej liczby wystąpień złożonej klasy.

Kompozycja rekurencyjna

Obiekty mogą być składane rekurencyjnie, a ich typ jest wtedy nazywany typem rekurencyjnym . Przykłady obejmują różne rodzaje drzew , DAG-ów i wykresów . Każdy węzeł w drzewie może być gałęzią lub liściem; innymi słowy, każdy węzeł jest drzewem w tym samym czasie, gdy należy do innego drzewa.

W UML skład rekurencyjny jest przedstawiany z asocjacją, agregacją lub kompozycją klasy z samą sobą.

Wzór kompozytowy

Kompozytowa konstrukcja wzór jest obiektowym projekt na podstawie typów kompozytowych, który łączy rekurencyjnych skład i pojemników realizować złożone hierarchie część-całość.

Typy kompozytowe w C

To jest przykład kompozycji w C .

struct Person
{
  int age;
  char name[20];
  enum {job_seeking, professional, non_professional, retired, student} employment;
};

W tym przykładzie typy pierwotne (niezłożone) int , enum {job_seeking, professional, non_professional, retired, student } i złożony typ tablicy char[] są łączone w celu utworzenia złożonej struktury Person . Każda struktura Osoby „ma” wtedy wiek, imię i rodzaj zatrudnienia.

Kalendarium kompozycji w różnych językach

C wywołuje rekord strukturą lub strukturą; języki zorientowane obiektowo , takie jak Java , Smalltalk i C++, często przechowują swoje rekordy ukryte wewnątrz obiektów ( instancji klas ); języki z rodziny ML nazywają je po prostu rekordami. COBOL był pierwszym szeroko rozpowszechnionym językiem programowania, który bezpośrednio wspierał rekordy; ALGOL 68 pobrał go z COBOL a Pascal , mniej więcej pośrednio, z ALGOL 68. Common Lisp dostarcza struktury i klasy (te ostatnie poprzez Common Lisp Object System ).

1959 – COBOL
      01  customer-record.
        03  customer-number     pic 9(8) comp.
        03  customer-name.
          05  given-names       pic x(15).
          05  initial-2         pic x.
          05  surname           pic x(15).
        03  customer-address.
          05  street.
            07  street-name     pic x(15).
              09  house-number  pic 999 comp.
          05  city              pic x(10).
          05  country-code      pic x(3).
          05  postcode          pic x(8).
        03  amount-owing        pic 9(8) comp.
1960 – ALGOL 60

Tablice były jedynym złożonym typem danych w Algolu 60 .

1964 – PL/I
dcl 1 newtypet based (P);
 2 (a, b, c) fixed bin(31),
 2 (i, j, k) float,
 2 r ptr;
allocate newtypet;
1968 – ALGOL 68
int max = 99;
mode newtypet = [0..9] [0..max]struct (
 long real a, b, c, short int i, j, k, ref real r
);
newtypet newarrayt = (1, 2, 3, 4, 5, 6, heap real := 7)

Na przykład połączona lista może być zadeklarowana jako:

mode node = union (real, int, compl, string),
 list = struct (node val, ref list next);

W przypadku ALGOL 68 tylko nazwa typu pojawia się po lewej stronie równości, a przede wszystkim konstrukcja jest wykonana – i może być odczytana – od lewej do prawej bez względu na priorytety.

1970 – Pascal
type
 a = array [1..10] of integer;
 b = record
  a, b, c: real;
  i, j, k: integer;
 end;
1972 – K&R C
#define max 99
struct newtypet {
  double a, b, c;
  float r;
  short i, j, k;
} newarrayt[10] [max + 1];
1977 – FORTRAN 77

Fortran 77 ma tablice, ale brakowało mu żadnych formalnych definicji rekordów/struktur. Zazwyczaj struktury złożone były budowane przy użyciu instrukcji EQUIVALENCE lub COMMON :

       CHARACTER NAME*32, ADDR*32, PHONE*16
       REAL OWING
       COMMON /CUST/NAME, ADDR, PHONE, OWING
1983 – Adaś
type Cust is
 record
  Name  : Name_Type;
  Addr  : Addr_Type;
  Phone : Phone_Type;
  Owing : Integer range 1..999999;
 end record;

Ada 95 wprowadziła koncepcje OOP poprzez typy oznaczone (odpowiednik klasy C++), Ada 2012 dodała obsługę weryfikacji podstawień poprzez kontrakty obejmujące całą klasę.

1983 - C ++
const int max = 99;
class {
  public:
  double a, b, c;
  float &r;
  short i, j, k;
}newtypet[10] [max + 1];
1991 – Python
max = 99
class NewTypeT:
    def __init__(self):
        self.a = self.b = self.c = 0
        self.i = self.j = self.k = 0.0
# Initialise an example array of this class.
newarrayt = [[NewTypeT() for i in range(max + 1)] for j in range(10)]
1992 – FORTRAN 90

Tablice i łańcuchy zostały odziedziczone z FORTRAN 77 i wprowadzono nowe słowo zastrzeżone: type

type newtypet
 double precision a, b, c
 integer*2 i, j, k
* No pointer type REF REAL R
 end type

type (newtypet) t(10, 100)

FORTRAN 90 zaktualizował i dołączył koncepcję FORTRAN IV o nazwie NAMELIST.

INTEGER :: jan = 1, feb = 2, mar = 3, apr = 4
NAMELIST / week / jan, feb, mar, apr
1994 – ANSI Wspólne Lisp

Common Lisp zapewnia struktury i dodane klasy CLOS w standardzie ANSI Common Lisp.

(defclass some-class ()
  ((f :type float)
   (i :type integer)
   (a :type (array integer (10)))))

Aby uzyskać więcej informacji na temat kompozycji w języku C/C++, zobacz Typ złożony .

Zbiór

Agregacja różni się od zwykłego składu tym, że nie oznacza własności. W kompozycji, gdy obiekt będący właścicielem jest zniszczony, tak samo są zawarte obiekty. W agregacji niekoniecznie jest to prawdą. Na przykład uniwersytet posiada różne wydziały (np. chemia ), a każdy wydział ma kilku profesorów. Jeśli uniwersytet zostanie zamknięty, wydziały przestaną istnieć, ale profesorowie na tych wydziałach nadal będą istnieć. Dlatego uniwersytet może być postrzegany jako kompozycja wydziałów, podczas gdy wydziały mają agregację profesorów. Ponadto profesor mógł pracować na więcej niż jednym wydziale, ale wydział nie mógł być częścią więcej niż jednej uczelni.

Kompozycja jest zwykle implementowana w taki sposób, że obiekt zawiera inny obiekt. Na przykład w C++ :

class Professor;  // Defined elsewhere

class Department {
 public:
  Department(const std::string& title): title_(title) {}

 private:
  // Aggregation: |Professors| may outlive the |Department|.
  std::vector<std::weak_ptr<Professor>> members_;
  const std::string title_;
};


class University {
 public:
  University() = default;

 private:
  // Composition: |Department|s exist only as long as the faculty exists.
  std::vector<Department> faculty_ = {
      Department("chemistry"),
      Department("physics"),
      Department("arts"),
  };
};

W agregacji obiekt może zawierać tylko odwołanie lub wskaźnik do obiektu (i nie może ponosić za to dożywotniej odpowiedzialności).

Czasami agregacja jest określana jako kompozycja, gdy rozróżnienie między zwykłym składem a agregacją jest nieistotne.

Powyższy kod przekształciłby się w następujący diagram klas UML:

Agregacja-Skład3.png

Agregacja w COM

Agregacja w COM

W Component Object Model firmy Microsoft agregacja oznacza, że ​​obiekt eksportuje, tak jakby był jego właścicielem, jeden lub kilka interfejsów innego obiektu, którego jest właścicielem. Formalnie jest to bardziej podobne do składu lub enkapsulacji niż do agregacji. Jednak zamiast implementować wyeksportowane interfejsy przez wywołanie interfejsów obiektu będącego własnością, same interfejsy obiektu będącego własnością są eksportowane. Posiadany obiekt jest odpowiedzialny za zapewnienie, że metody tych interfejsów odziedziczonych z IUnknown faktycznie wywołują odpowiednie metody właściciela. Ma to zagwarantować, że liczba odwołań właściciela jest poprawna i wszystkie interfejsy właściciela są dostępne za pośrednictwem wyeksportowanego interfejsu, podczas gdy żadne inne (prywatne) interfejsy posiadanego obiektu nie są dostępne.

Zobacz też

Bibliografia

Linki zewnętrzne