Jaki jest pomysł nazewnictwa klas za pomocą sufiksu „Info”, na przykład: „SomeClass” i „SomeClassInfo”?

20

Pracuję w projekcie, który dotyczy urządzeń fizycznych i byłem zdezorientowany, jak prawidłowo nazwać niektóre klasy w tym projekcie.

Biorąc pod uwagę fakt, że rzeczywiste urządzenia (czujniki i odbiorniki) to jedno, a ich reprezentacja w oprogramowaniu jest inna, myślę o nadaniu nazw niektórym klasom za pomocą wzorca nazwy sufiksu „Info”.

Na przykład, podczas gdy a Sensorbyłby klasą reprezentującą rzeczywisty czujnik (gdy jest on faktycznie podłączony do jakiegoś działającego urządzenia), SensorInfobyłby użyty do przedstawienia jedynie cech takiego czujnika. Na przykład, po zapisaniu pliku, serializowałbym a SensorInfodo nagłówka pliku, zamiast serializować a Sensor, co nie miałoby nawet sensu.

Ale teraz jestem zdezorientowany, ponieważ w cyklu życia obiektów istnieje pole środkowe, w którym nie mogę zdecydować, czy mam użyć jednego lub drugiego, jak uzyskać jeden od drugiego, a nawet czy oba warianty powinny być rzeczywiście zwinięte tylko do jednej klasy.

Ponadto, zbyt powszechna przykładowa Employeeklasa oczywiście jest po prostu reprezentacją prawdziwej osoby, ale EmployeeInfoo ile wiem , nikt nie sugerowałby, aby nazwać klasę .

Językiem, w którym pracuję, jest .NET, a ten schemat nazewnictwa wydaje się być powszechny w całym frameworku, na przykład w przypadku tych klas:

  • Directoryi DirectoryInfoklasy;
  • Filei FileInfoklasy;
  • ConnectionInfoklasa (bez odpowiedniej Connectionklasy);
  • DeviceInfoklasa (bez odpowiedniej Deviceklasy);

Więc moje pytanie brzmi: czy istnieje powszechne uzasadnienie używania tego wzorca nazewnictwa? Czy istnieją przypadki, w których sensowne jest posiadanie par nazw ( Thingi ThingInfo) oraz inne przypadki, w których powinna istnieć tylko ThingInfoklasa lub Thingklasa, bez jej odpowiednika?

heltonbiker
źródło
5
Ben Aaronson miał rację w swojej odpowiedzi poniżej; Infosufiks odróżnia staticklasy zawierającej metody narzędzia z jego pełnostanową odpowiednik. Nie jest to „najlepsza praktyka” jako taka; to tylko sposób, w jaki zespół .NET wymyślił rozwiązanie konkretnego problemu. Mogli tak łatwo wymyślić FileUtilityi File, ale File.DoSomething()i FileInfo.FileNamewydają się czytać lepiej.
Robert Harvey
1
Warto zauważyć, że jest to powszechny wzorzec, ale z tyloma różnymi konwencjami nazewnictwa, ile jest języków i interfejsów API. Na przykład w Javie, jeśli masz klasę stanową Foo, możesz mieć klasę użyteczności, której nie da się utworzyć Foos. Jeśli chodzi o nazewnictwo, ważna jest spójność w interfejsie API, a najlepiej w interfejsach API na platformie.
Kevin Krumwiede,
1
Naprawdę? „Nikt nie sugeruje, aby nazwać klasę EmployeeInfo”? NIKT? To wydaje się trochę mocne w przypadku czegoś nie tak oczywistego.
ThePopMachine
@ThePopMachine Zgadzam się, że słowo „nikt” może w tym przypadku nie być zbyt trudne, ale Employeedziesiątki znajdują przykłady w Internecie lub w klasycznych książkach, których jeszcze nie widziałem EmployeeInfo(być może dlatego, że pracownik jest żywą istotą, a nie konstrukcja techniczna, taka jak połączenie lub plik). EmployeeInfoZgadzam się jednak, że jeśli klasa miałaby zostać zaproponowana w projekcie, wierzę, że mogłaby się przydać.
heltonbiker

Odpowiedzi:

21

Myślę, że „informacje” to mylne określenie. Obiekty mają stan i akcje: „informacje” to po prostu inna nazwa „stanu”, który jest już zapisany w OOP.

Co naprawdę próbujesz tutaj wymodelować? Potrzebujesz obiektu reprezentującego sprzęt w oprogramowaniu, aby inny kod mógł z niego korzystać.

Łatwo to powiedzieć, ale jak się dowiedziałeś, jest w tym coś więcej. „Sprzęt reprezentujący” jest zaskakująco szeroki. Obiekt, który to robi, ma kilka obaw:

  • Niski poziom komunikacji z urządzeniem, niezależnie od tego, czy chodzi o interfejs USB, port szeregowy, TCP / IP, czy połączenie własnościowe.
  • Stan zarządzania Czy urządzenie jest włączone? Gotowy do rozmowy z oprogramowaniem? Zajęty?
  • Obsługa zdarzeń. Urządzenie wygenerowało dane: teraz musimy wygenerować zdarzenia, aby przekazać je innym zainteresowanym klasom.

Niektóre urządzenia, takie jak czujniki, będą miały mniej problemów niż, powiedzmy, urządzenie wielofunkcyjne drukarka / skaner / faks. Czujnik prawdopodobnie po prostu wytwarza strumień bitów, podczas gdy złożone urządzenie może mieć złożone protokoły i interakcje.

Wracając do konkretnego pytania, istnieje kilka sposobów, aby to zrobić, w zależności od konkretnych wymagań, a także złożoności interakcji sprzętowej.

Oto przykład, w jaki sposób zaprojektowałbym hierarchię klas dla czujnika temperatury:

  • ITemperatureSource: interfejs, który reprezentuje wszystko, co może generować dane dotyczące temperatury: czujnik, może nawet być opakowaniem pliku lub danymi zakodowanymi na stałe (pomyśl: testy próbne).

  • Acme4680Sensor: czujnik ACME model 4680 (doskonały do ​​wykrywania, gdy Roadrunner jest w pobliżu). Może to implementować wiele interfejsów: być może ten czujnik wykrywa zarówno temperaturę, jak i wilgotność. Ten obiekt zawiera stan na poziomie programu, taki jak „czy czujnik jest podłączony?” i „jakie było ostatnie czytanie?”

  • Acme4680SensorComm: służy wyłącznie do komunikacji z urządzeniem fizycznym. Nie utrzymuje stanu. Służy do wysyłania i odbierania wiadomości. Ma metodę C # dla każdego komunikatu rozumianego przez sprzęt.

  • HardwareManager: służy do pobierania urządzeń. Jest to zasadniczo fabryka buforująca instancje: dla każdego urządzenia sprzętowego powinna istnieć tylko jedna instancja obiektu urządzenia. Musi być wystarczająco inteligentny, aby wiedzieć, że jeśli wątek A zażąda czujnika temperatury ACME, a wątek B zażąda czujnika wilgotności ACME, są one w rzeczywistości tym samym obiektem i powinny zostać zwrócone do obu wątków.


Na najwyższym poziomie będziesz mieć interfejsy dla każdego typu sprzętu. Opisują działania, które Twój kod C # podejmowałby na urządzeniach, używając typów danych C # (nie np. Tablice bajtów, których mógłby użyć surowy sterownik urządzenia).

Na tym samym poziomie masz klasę wyliczenia z jedną instancją dla każdego typu sprzętu. Czujnik temperatury może być jednym typem, czujnik wilgotności innym.

Jeden poziom poniżej to rzeczywiste klasy, które implementują te interfejsy: reprezentują one jedno urządzenie podobne do Acme4680Sensor, który opisałem powyżej. Każda konkretna klasa może implementować wiele interfejsów, jeśli urządzenie może wykonywać wiele funkcji.

Każda klasa urządzeń ma swoją prywatną klasę Comm (komunikacyjną), która obsługuje niskopoziomowe zadanie mówienia do sprzętu.

Poza modułem sprzętowym jedyną widoczną warstwą są interfejsy / wyliczanie oraz HardwareManager. Klasa HardwareManager to abstrakcja fabryczna, która obsługuje tworzenie instancji klas urządzeń, buforowanie instancji ( naprawdę nie chcesz, aby dwie klasy urządzeń rozmawiały z tym samym urządzeniem sprzętowym) itp. Klasa, która potrzebuje określonego typu czujnika, prosi HardwareManager o pobranie urządzenie dla konkretnego wyliczenia, które następnie sprawdza, czy jest już utworzone, jeśli nie, jak je utworzyć i zainicjować itp.

Celem jest oddzielenie logiki biznesowej od logiki sprzętowej niskiego poziomu. Kiedy piszesz kod, który drukuje dane czujnika na ekranie, kod ten nie powinien dbać o to, jaki typ czujnika masz , i tylko wtedy, gdy to oddzielenie jest na miejscu, co koncentruje się na tych interfejsach sprzętowych.


Przykładowy diagram klasy UML pokazujący projekt opisany w tej odpowiedzi

Uwaga: istnieją powiązania między HardwareManager a każdą klasą urządzeń, której nie narysowałem, ponieważ diagram zmieniłby się w zupę strzałkową.


źródło
Bardzo interesująca odpowiedź. Poprosiłbym o szybką edycję: pozostaw wyraźniejsze, jakie jest dziedzictwo / powstrzymanie / współpraca między czterema wspomnianymi klasami. Dziękuję Ci bardzo!
heltonbiker
Dodałem diagram klas UML. czy to pomaga?
2
Powiedziałbym, że to zabójcza odpowiedź i nie tylko bardzo mi pomoże, ale wierzę, że mogłaby pomóc znacznie większej liczbie ludzi w przyszłości. Poza tym przykład hierarchii klas, który podajesz, wyjątkowo dobrze odwzorowuje nasze domeny problemów i rozwiązań. Jeszcze raz, wielkie dzięki!
heltonbiker
Kiedy przeczytałem pytanie, zdałem sobie sprawę, że dzieje się więcej, więc trochę przesadziłem i podzieliłem się całym projektem. Jest to coś więcej niż prosty problem z nazewnictwem, ponieważ nazwy wskazują na projekt. Pracowałem z systemami zbudowanymi w ten sposób i działały one dość dobrze.
11

To może być trochę trudne do znalezienia Jednolita konwencja jednoczącej się tutaj, ponieważ klasy te są rozłożone na wiele nazw, ( ConnectionInfowydaje się być CrystalDecisions, a DeviceInfow System.Reporting.WebForms).

Patrząc na te przykłady, wydaje się, że istnieją dwa różne zastosowania sufiksu:

  • Odróżnianie klasy zapewniającej metody statyczne za pomocą klasy zapewniającej metody instancji. Jest tak w przypadku System.IOklas, co podkreślono w ich opisach:

    Katalog :

    Udostępnia statyczne metody tworzenia, przenoszenia i wyliczania w katalogach i podkatalogach. Ta klasa nie może być dziedziczona.

    DirectoryInfo :

    Udostępnia metody instancji do tworzenia, przenoszenia i wyliczania w katalogach i podkatalogach. Ta klasa nie może być dziedziczona.

    Infowydaje się tutaj nieco dziwnym wyborem, ale czyni względnie wyraźną różnicę: Directoryklasa może w uzasadniony sposób albo reprezentować konkretny katalog, albo zapewniać ogólne metody pomocnicze związane z katalogiem bez utrzymywania żadnego stanu, podczas gdy DirectoryInfonaprawdę może być tylko tym pierwszym.

  • Podkreślając, że klasa zawiera tylko informacje i nie zapewnia zachowania, którego można zasadnie oczekiwać po nazwie bez przyrostka .

    Myślę, że ostatnia część tego zdania może być fragmentem układanki, która odróżnia, powiedzmy, ConnectionInfood EmployeeInfo. Gdybym miał wywoływaną klasę Connection, słusznie oczekiwałbym, że zapewni mi funkcjonalność, jaką ma połączenie - szukałbym metod takich jak void Open()itp. Jednak nikt przy zdrowych zmysłach nie spodziewałby się, że Employeeklasa faktycznie rób to, co Employeerobi prawdziwy , lub szukaj metod takich jak void DoPaperwork()lub bool TryDiscreetlyBrowseFacebook().

Ben Aaronson
źródło
1
Bardzo dziękuję za odpowiedź! Wierzę, że pierwszy punkt w twojej odpowiedzi zdecydowanie opisuje to, co dzieje się w klasach .NET, ale drugi ma większą wartość (a przy okazji jest inny), ponieważ lepiej ujawnia zamierzoną abstrakcję: rzecz do użycia vs. rzecz do opisania. Trudno było wybrać odpowiedź do zaakceptowania.
heltonbiker
4

Ogólnie rzecz biorąc, Infoobiekt kapsułkuje informacje o stanie obiektu w pewnym momencie . Jeśli poproszę system, aby spojrzał na plik i podał mi FileInfoobiekt powiązany z jego rozmiarem, oczekiwałbym, że ten obiekt zgłosi rozmiar pliku w momencie wysłania żądania (lub ściślej mówiąc, rozmiar plik w pewnym momencie między nawiązaniem połączenia a jego zwrotem). Jeśli rozmiar pliku zmienia się między momentem powrotu żądania a momentem FileInfosprawdzenia obiektu, nie spodziewałbym się, że taka zmiana zostanie odzwierciedlona w FileInfoobiekcie.

Zauważ, że to zachowanie byłoby bardzo różne od zachowania Fileobiektu. Jeśli żądanie otwarcia pliku dyskowego w trybie niewyłącznym zwróci Fileobiekt, który ma Sizewłaściwość, oczekiwałbym, że wartość zwrócona w ten sposób zmieni się, gdy zmieni się rozmiar pliku dyskowego, ponieważ Fileobiekt nie reprezentuje jedynie stanu plik - reprezentuje sam plik .

W wielu przypadkach obiekty dołączane do zasobu muszą zostać wyczyszczone, gdy ich usługi nie są już potrzebne. Ponieważ *Infoobiekty nie dołączają się do zasobów, nie wymagają czyszczenia. W konsekwencji, w przypadkach, gdy Infoobiekt spełni wymagania klienta, może być lepiej, aby kod używał jednego, niż użyć obiektu, który reprezentowałby zasób bazowy, ale którego połączenie z tym zasobem musiałoby zostać wyczyszczone.

supercat
źródło
1
To nie jest dokładnie tak, ale nie wydaje się, aby wyjaśnić wzorce nazewnictwa .NET jest bardzo dobrze w ogóle, ponieważ Fileklasa nie może być instancja i FileInfoobiekty zrobić aktualizację z bazowego systemu plików.
Nathan Tuggy
@NathanTuggy Zgadzam się, że nie jest to dobrze związane z tą konwencją nazewnictwa w .NET, ale jeśli chodzi o mój obecny problem, uważam, że jest to bardzo istotne i może doprowadzić do spójnego rozwiązania. Poparłem tę odpowiedź, ale trudno jest wybrać tylko jedną, która będzie akceptowana ...
heltonbiker
@NathanTuggy: Nie polecałbym używania .NET jako modelu jakiejkolwiek spójności. To dobry i użyteczny Framework, który zawiera wiele dobrych pomysłów, ale kilka złych pomysłów zostaje również schwytanych w miksie.
supercat
@supercat: Sure; po prostu dziwnie jest odpowiedzieć na pytanie „dlaczego .NET robi to w ten sposób?” z „byłoby dobrym pomysłem robić rzeczy% THIS_WAY%”.
Nathan Tuggy
@NathanTuggy: Nie pamiętałem dokładnych danych klas, ale myślałem, że FileInfopo prostu przechowuję statyczne informacje. Czyż nie Ponadto nigdy nie miałem okazji otwierać plików w trybie niewyłącznym, ale powinno to być możliwe i oczekiwałbym, że istnieje metoda, która zgłosi bieżący rozmiar pliku, nawet jeśli obiekt użyty do otwarcia nie jest nazywane File(zwykle po prostu użyć ReadAllBytes, WriteAllBytes, ReadAllText, WriteAllText, itd.).
supercat
2

Biorąc pod uwagę fakt, że rzeczywiste urządzenia (czujniki i odbiorniki) to jedno, a ich reprezentacja w oprogramowaniu jest inna, myślę o nadaniu nazw niektórym klasom za pomocą wzorca nazwy sufiksu „Info”.

Na przykład, podczas gdy a Sensorbyłby klasą reprezentującą rzeczywisty czujnik (gdy jest on faktycznie podłączony do jakiegoś działającego urządzenia), SensorInfobyłby użyty do przedstawienia jedynie cech takiego czujnika. Na przykład, po zapisaniu pliku, serializowałbym a SensorInfodo nagłówka pliku, zamiast serializować a Sensor, co nie miałoby nawet sensu.

Nie podoba mi się to rozróżnienie. Wszystkie obiekty są „reprezentacjami w oprogramowaniu”. To właśnie oznacza słowo „przedmiot”.

Teraz sensowne może być oddzielenie informacji o urządzeniu peryferyjnym od rzeczywistego kodu, który łączy się z urządzeniem peryferyjnym. Na przykład Sensor ma SensorInfo, który zawiera większość zmiennych instancji, wraz z niektórymi metodami, które nie wymagają sprzętu, podczas gdy klasa Sensor jest odpowiedzialna za faktyczną interakcję z czujnikiem fizycznym. Nie masz, Sensorchyba że komputer ma czujnik, ale prawdopodobnie masz SensorInfo.

Problem polega na tym, że tego rodzaju projekty można uogólnić na (prawie) dowolne klasy. Musisz więc uważać. Na przykład oczywiście nie miałbyś SensorInfoInfoklasy. A jeśli masz Sensorzmienną, możesz naruszać prawo Demeter, wchodząc w interakcje z jego SensorInfoczłonkiem. To oczywiście nie jest fatalne, ale projektowanie API nie jest przeznaczone tylko dla autorów bibliotek. Jeśli utrzymasz własny interfejs API w czystości i prosty, kod będzie łatwiejszy w utrzymaniu.

Zasoby systemu plików, takie jak katalogi, moim zdaniem są bardzo zbliżone do tej krawędzi. Są sytuacje, w których chcesz opisać katalog, który nie jest lokalnie dostępny, to prawda, ale przeciętny programista prawdopodobnie nie znajduje się w żadnej z tych sytuacji. Komplikowanie struktury klas w ten sposób jest moim zdaniem nieprzydatne. Porównaj podejście Pythona w pathlib: Istnieje jedna klasa, która „najprawdopodobniej jest potrzebna” oraz różne klasy pomocnicze, które większość programistów może bezpiecznie zignorować. Jeśli jednak naprawdę ich potrzebujesz, zapewniają one w dużej mierze ten sam interfejs, z pominięciem konkretnych metod.

Kevin
źródło
Dziękuję za odpowiedź i podziękowania za konstrukcję typu „have-a”;) Twoja odpowiedź przypomina mi o dyskomforcie spowodowanym przez koncepcję „DTO” (Data Transfer Object) - lub jej rodzeństwo obiektu parametru - co jest niezadowolone. bardziej ortodoksyjni fanatycy OO, ponieważ zwykle nie zawierają metod (w końcu jest to obiekt do przesyłania danych ). W tym sensie i podsumowując również to, co powiedzieli inni, myślę, że SensorInfobyłby to rodzaj DTO i / lub też jak „migawka”, a nawet „specyfikacja”, reprezentująca tylko część danych / stanów rzeczywistego Sensorobiektu że „może nawet tam nie być”.
heltonbiker
Podobnie jak w przypadku większości problemów projektowych, nie ma twardych i szybkich reguł. W podanym przeze mnie przykładzie pathlib PureWindowsPathdziała trochę jak obiekt Info, ale ma metody wykonywania rzeczy, które nie wymagają systemu Windows (np. Przejęcie podkatalogu, podzielenie rozszerzenia pliku itp.). Jest to bardziej pomocne niż tylko dostarczenie gloryfikowanej struktury.
Kevin
1
Jeszcze raz, podziękowania za część „glorified struct” :). Przypomina mi to podobny cytat z książki „Czysty kod” wuja Boba, rozdział 6: „Dojrzali programiści wiedzą, że idea, że ​​wszystko jest przedmiotem, jest mitem. Czasami naprawdę potrzebujesz prostych struktur danych z działającymi na nich procedurami”.
heltonbiker
2

Powiedziałbym, że kontekst / domena ma znaczenie, ponieważ mamy wysoki kod logiki biznesowej i modele niskiego poziomu, komponenty architektury i tak dalej ...

„Informacje”, „Dane”, „Menedżer”, „Obiekt”, „Klasa”, „Model”, „Kontroler” itp. Mogą być śmierdzącymi przyrostkami, szczególnie na niższym poziomie, ponieważ każdy obiekt ma pewne informacje lub dane, więc ta informacja nie jest konieczna.

Nazwy klas domeny biznesowej powinny wyglądać tak, jak mówią o tym wszyscy interesariusze, bez względu na to, czy brzmi to dziwnie, czy nie jest w 100% poprawnym językiem.

Dobre przyrostki dla struktur danych to np. „Lista”, „Mapa” i wzorce podpowiedzi „Dekorator”, „Adapter”, jeśli uważasz, że jest to konieczne.

W twoim scenariuszu z czujnikami nie spodziewałbym SensorInfosię, że zapiszę twój czujnik, ale SensorSpec. InfoImho jest bardziej pochodną informacją, podobnie FileInfojak rozmiar, którego nie zapisujesz lub ścieżka pliku zbudowana ze ścieżki i nazwy pliku itp.

Kolejny punkt:

W informatyce są tylko dwie trudne rzeczy: unieważnienie pamięci podręcznej i nadawanie nazw.

- Phil Karlton

To zawsze przypomina mi myślenie o nazwisku przez kilka sekund, a jeśli go nie znalazłem, używam dziwnych imion i oznaczam je „DO ZROBIENIA”. Zawsze mogę to zmienić później, ponieważ moje IDE zapewnia obsługę refaktoryzacji. To nie jest slogan firmowy, który musi być dobry, ale tylko trochę kodu, który możemy zmieniać za każdym razem, kiedy chcemy. Miej to w pamięci.

H
źródło
1

ThingInfo może służyć jako świetny serwer proxy tylko do odczytu dla rzeczy.

patrz http://www.dofactory.com/net/proxy-design-pattern

Proxy: „Podaj surogat lub symbol zastępczy dla innego obiektu, aby kontrolować dostęp do niego”.

Zwykle ThingInfo ma właściwości publiczne bez ustawień. Z tych klas i metod w klasie można bezpiecznie korzystać i nie będą one wprowadzać żadnych zmian w danych kopii zapasowej, obiekcie ani innych obiektach. Nie wystąpią żadne zmiany stanu ani inne skutki uboczne. Mogą być używane do raportowania i usług internetowych lub w dowolnym miejscu, w którym potrzebujesz informacji o obiekcie, ale chcesz ograniczyć dostęp do samego obiektu.

Używaj ThingInfo, gdy tylko jest to możliwe, i ogranicz użycie rzeczywistej Rzeczy do czasów, w których faktycznie potrzebujesz zmienić obiekt Thing. Dzięki temu czytanie i debugowanie jest znacznie szybsze, gdy przyzwyczaisz się do korzystania z tego wzorca.

Shmoken
źródło
Doskonały. Wcześniej dzisiaj analizowałem moje potrzeby architektoniczne, dotyczące klas, których użyłem w pytaniu, i doszedłem do tego samego wniosku. W moim przypadku mam, Receiverktóry odbiera strumienie danych z wielu Sensors. Chodzi o to, że odbiornik powinien wyodrębnić rzeczywiste czujniki. Problem polega jednak na tym, że potrzebuję informacji o czujniku, aby móc zapisać je w nagłówku pliku. Rozwiązanie: każdy IReceiverbędzie miał listę SensorInfo. Jeśli wyślę do odbiornika polecenia, które sugerują zmianę stanu czujnika, zmiany te zostaną odzwierciedlone (przez getter) na odpowiednim SensorInfo.
heltonbiker
(ciąg dalszy ...) to znaczy: nie rozmawiam z samymi czujnikami, rozmawiam tylko z Odbiornikiem za pomocą poleceń wyższego poziomu, a Odbiornik z kolei rozmawia z każdym z Czujników. Ale w końcu potrzebuję informacji z czujników, które otrzymuję z instancji Odbiornika poprzez jego List<SensorInfo>właściwość tylko do odczytu.
heltonbiker
1

Jak dotąd nikt w tym pytaniu nie zdawał sobie sprawy z prawdziwego powodu tej konwencji nazewnictwa.

DirectoryInfoNie jest katalogiem. Jest DTO z danymi na temat katalogu. Może istnieć wiele takich przypadków opisujących ten sam katalog. To nie jest byt. Jest to obiekt o wartości wyrzucanej. A nie reprezentuje rzeczywistego katalogu. Możesz również myśleć o tym jak o uchwycie lub kontrolerze katalogu.DirectoryInfo

Porównaj to z klasą o nazwie Employee. Może to być obiekt jednostki ORM i jest to pojedynczy obiekt opisujący tego pracownika. Jeśli był to obiekt wartości bez tożsamości, należy go wywołać EmployeeInfo. EmployeeRzeczywiście nie reprezentuje rzeczywistą pracownika. Wywołana klasa DTO podobna do wartości EmployeeInfowyraźnie nie reprezentowałaby pracownika, ale raczej opisywałaby go lub przechowywała dane na jego temat.

W BCL istnieje przykład, w którym istnieją obie klasy: A ServiceControllerto klasa opisująca usługę Windows. Dla każdej usługi może istnieć dowolna liczba takich kontrolerów. A ServiceBase(lub klasa pochodna) jest faktyczną usługą i koncepcyjnie nie ma sensu mieć wielu jej instancji dla każdej odrębnej usługi.

usr
źródło
Brzmi podobnie do Proxywzorca wspomnianego przez @Shmoken, prawda?
heltonbiker
@heltonbiker niekoniecznie musi to być serwer proxy. Może to być obiekt, który nie jest w żaden sposób powiązany z opisywaną rzeczą. Na przykład możesz otrzymać EmployeeInfoz usługi internetowej. To nie jest proxy. Kolejny przykład: An AddressInfonawet nie ma rzeczy, którą mógłby proxy, ponieważ adres nie jest bytem. Jest to samodzielna wartość.
usr
1
Rozumiem, to ma sens!
heltonbiker