Czy obiekty w OOP muszą reprezentować byt?


82

Czy obiekt musi reprezentować byt?

Przez podmiot mam na myśli coś takiego jak Product, Motor, A ParkingLotitd, fizyczne, a nawet jednoznaczne niefizyczne koncepcyjne przedmiot - coś, co jest dobrze zdefiniowany, a niektóre podstawowe dane wyraźnie należący do obiektu, a niektóre funkcje / metody które wyraźnie działają na podstawowych danych.

Na przykład, mogę mieć obiekt Demon, byt sam w sobie, być może wyimaginowany i nie fizyczny, ale byt jednak

Czy obiekt może być tylko zbiorem metod , wspólnym zestawem procedur, które wiążą się ze wspólnym celem?

Przykład: można wywołać klasę MotorOperationslub MotorActions, gdy nie ma encji, ale metody wewnątrz klasy robią takie rzeczy

  • getMotorDataFromHTMLForm ()
  • getMotorManufacts ()
  • selectMotorFromUserRequirements (wymagania $)
  • canMotorCanHandleOperatingConditions (warunki $)
  • computePowerConsumptionForMotor ($ id)

Klasa jest zazwyczaj definiowana jako centralna dla obiektu + operacje na danych. Na przykład Motormogą istnieć pewne zmienne motoryczne dotyczące specyfikacji silnika i mogą istnieć operacje, które łączą te dane, aby coś wytworzyć.

W moim przypadku bardziej przypomina to, że mam klasę z operacjami na danych + dane przekazywane przez klasę, nie ma danych skoncentrowanych na „operacjach motorycznych”, innych niż tymczasowe przekazywanie danych przez klasę.

Pytanie

Czy klasy mogą reprezentować obiekty bez bytów? Jeśli nie, dlaczego są złe / niepełne / nie koncentrują się na OOP? Czy istnieją sposoby, które należy zmienić / ulepszyć koncepcyjnie, aby były zgodne z OOP?


2
+1. Ale czy „tak” oznacza, że ​​musi reprezentować byt, czy może oznaczać, że mogą reprezentować obiekty bez bytu?
Panzercrisis,

1
Najpierw przychodzi mi na myśl: java.awt i jego klasy „Op” (np. Docs.oracle.com/javase/7/docs/api/java/awt/image/… ), jeśli o to ci chodzi. Reprezentuje operację. Teraz nie jestem pewien, czy to dobra praktyka (wygląda dziwnie i brzydko), ale jest zawarta w standardowej bibliotece Java, a Java to OOP. Przez większą część.
Łukasz

1
Nie, nie robi to, ale to nie znaczy MotorActionsani nie MotorOperationssą dobre pomysły, czy nie.
immibis

1
To pytanie mogłoby skorzystać z dalszej specyfikacji puszki .
reinierpost

3
@ Dennis Naprawdę czuję, że zadajesz wszystkie złe pytania. Po pierwsze dlatego, że nie ma jednej definitywnej definicji OOP, po drugie dlatego, że paradygmaty są jedynie środkiem do celu. Jedyne ważne pytania to: „czy pisanie kodu w ten sposób ułatwia rozumowanie jego poprawności?” oraz „czy pisanie kodu w ten sposób ułatwia ponowne użycie?”
Doval,

Odpowiedzi:


109

Nie , obiekt nie musi reprezentować bytu.

W rzeczywistości argumentowałbym, że kiedy przestajesz myśleć o przedmiotach jako o fizycznych bytach, to w końcu dostajesz korzyści, które obiecuje OOP.

To nie jest najlepszy przykład, ale projekt ekspresu do kawy jest prawdopodobnie miejscem, w którym zaczęło mi się świecić światło.

Obiekty dotyczą wiadomości. Chodzi o obowiązki. Nie dotyczą samochodów, użytkowników ani zamówień.

Wiem, że uczymy OO w ten sposób, ale po kilku próbach staje się oczywiste, jak frustrujące jest zastanawianie się, dokąd zmierzają rzeczy, gdy próbujesz robić MVC, MVVM lub MVW cokolwiek. Albo twoje modele staną się śmiesznie rozdęte, albo zrobią to twoje kontrolery. Jeśli chodzi o nawigację, dobrze jest wiedzieć, że wszystko, co dotyczy pojazdów, znajduje się w pliku Vehicle.ext, ale gdy twoja aplikacja dotyczy pojazdów, nieuchronnie kończy się na 3000 linii spaghetti w tym pliku.

Kiedy masz nową wiadomość do wysłania, masz co najmniej jeden nowy obiekt i być może ich parę. Więc w twoim pytaniu o pakiet metod argumentowałbym, że potencjalnie mówisz o pakiecie wiadomości. I każdy z nich może być swoim własnym przedmiotem, z własną pracą do wykonania. I to jest w porządku. Stanie się oczywiste, gdy rozdzielisz różne rzeczy, które naprawdę naprawdę muszą być razem. I złożyłeś je razem. Ale nie od razu umieszczasz każdą metodę w niejasnej szufladzie dla wygody, jeśli chcesz cieszyć się OO.

Porozmawiajmy o workach funkcji

Obiekt może być tylko zbiorem metod i nadal być OO, ale moje „reguły” są dość surowe.

  1. Kolekcja powinna ponosić jedną odpowiedzialność, a odpowiedzialność ta nie może być tak ogólna, jak „Robi rzeczy dla silników”. Mogę zrobić coś takiego jak fasada warstwy usługowej, ale jestem świadomy, że jestem leniwy z powodów związanych z nawigacją / odkryciem, a nie dlatego, że próbuję napisać kod OO.

  2. Wszystkie metody powinny mieć spójną warstwę abstrakcji. Jeśli jedna metoda pobiera obiekty Motorowe, a druga zwraca Moc, to prawdopodobnie jest to zbyt daleko od siebie.

  3. Obiekt powinien działać na tym samym „rodzaju” danych. Ten obiekt robi rzeczy dla silników (start / stop), ten robi rzeczy z długością korby, ten obsługuje sekwencjonowanie zapłonu, ten ma postać HTML. Dane te mogą być polami na obiekcie i wydają się spójne.

Generalnie buduję tego typu obiekty, kiedy wykonuję transformacje, kompozycje lub po prostu nie chcę się martwić o zmienność.

Uważam, że skupienie się na odpowiedzialności za przedmiot prowadzi mnie do spójności. Aby być przedmiotem, musi istnieć pewna spójność, ale nie musi być żadnych pól ani bardzo dużego zachowania, aby mógł on być przedmiotem. Gdybym budował system, który potrzebowałby 5 metod motorycznych, zaczynałbym od 5 różnych obiektów, które robią te rzeczy. Gdy znalazłem podobieństwo, zacząłem łączyć rzeczy ze sobą lub używać wspólnych obiektów „pomocniczych”. To porusza mnie do otwartych / zamkniętych problemów - jak mogę wyodrębnić ten kawałek funkcjonalności, aby nigdy więcej nie musiałem modyfikować tego konkretnego pliku, ale nadal go używać w razie potrzeby?

Obiekty dotyczą wiadomości

Pola prawie nie mają znaczenia dla obiektu - pobieranie i ustawianie rejestrów nie zmienia świata poza programem. Współpraca z innymi obiektami kończy pracę. Jednak siłą OO jest to, że możemy tworzyć abstrakcje, abyśmy nie musieli myśleć o wszystkich pojedynczych szczegółach jednocześnie. Abstrakcje, które przeciekają lub nie mają sensu, są problematyczne, dlatego głęboko (prawdopodobnie za dużo) myślimy o tworzeniu obiektów pasujących do naszych modeli mentalnych.

Kluczowe pytanie: dlaczego te dwa obiekty muszą ze sobą rozmawiać?

Pomyśl o obiekcie jako o organie w człowieku - ma on domyślny cel i zmienia zachowanie tylko wtedy, gdy otrzyma określony komunikat, na którym mu zależy.

Wyobraź sobie scenariusz, w którym jesteś na przejściu dla pieszych i samochód jedzie szybko. Jako obiekt mózgu wykrywam stresor. Mówię podwzgórzowi, aby wysłał hormon uwalniający kortykotrofinę. Przysadka mózgowa otrzymuje tę wiadomość i uwalnia hormon kortykotroficzny nadnerczy. Nadnercza otrzymują tę wiadomość i wytwarzają adrenalinę. Kiedy obiekt mięśniowy otrzymuje ten komunikat adrenaliny, kurczy się. Kiedy serce otrzymuje tę samą wiadomość, bije szybciej. Cały łańcuch graczy jest zaangażowany w rozpoczęcie złożonego zachowania podczas sprintu po drugiej stronie ulicy i ważne są przesłania. Obiekt mózgu wie, jak doprowadzić podwzgórze do wysłania ostrzeżenia, ale nie zna łańcucha obiektów, które ostatecznie spowodują zachowanie. Podobnie serce nie ma pojęcia, skąd pochodzi adrenalina,

Zatem w tym ( uproszczonym ) przykładzie obiekt nadnerczy musi tylko wiedzieć, jak przyjmować ACTH i wytwarzać adrenalinę. Nie potrzebuje do tego żadnych pól, ale nadal wydaje mi się, że to jakiś przedmiot.

Teraz, jeśli nasza aplikacja jest przeznaczona tylko do sprintu po drugiej stronie ulicy, może nie potrzebuję przysadki mózgowej i obiektów nadnerczy. Albo potrzebuję tylko obiektu przysadki mózgowej, który wykonuje tylko niewielką część tego, co możemy koncepcyjnie postrzegać jako „model przysadki mózgowej”. Wszystkie te koncepcje istnieją jako byty koncepcyjne, ale jest to oprogramowanie i możemy zrobić AdrenalineSender lub MuscleContractor lub cokolwiek innego i nie martwić się zbytnio o „niekompletność” naszego modelu.


4
Zgadzam się z faktyczną treścią tej odpowiedzi, ale wydaje mi się, że źle rozumie pytanie. W szczególności pytanie obejmuje w bycie „lub pojęcie, coś, co jest dobrze zdefiniowane”. Kontrprzykładami tego są „ MotorOperationslub MotorActions”. Z tego jestem pewien, że zarówno oryginalne, jak i końcowe projekty klas z przykładu CoffeeMaker mieszczą się w definicji OP „reprezentującej byt”
Ben Aaronson

1
Postmodernistyczna architektura systemu DCI radzi sobie z tym bez ekstremalnych abstrakcji stworzonych przez inżynierów kochających strukturę. Komputer powinien myśleć, co myśli użytkownik, a nie na odwrót. fulloo.info/doku.php?id=what_is_dci
ciscoheat

@BenAaronson Wydaje mi się, że możesz ewoluować do tego obiektu jako spójnej koncepcji przy wystarczającym wspólnym wysiłku, ale zauważyłem tendencję do skupiania się na bytach, aby wymusić rzeczy, które powinny być od siebie oddzielone. Istoty zachęcają granice w naszych imionach, co jest dobre, ale także niosą ze sobą pojęcie poprawności / kompletności, które zwykle boli. W najbardziej absurdalnych terminach opowiadam się za obiektem FirstNameValidator i przeciwko obiektowi Name, który sprawdza również imię i nazwisko.
Steve Jackson,


2
W przedmiotach chodzi o wiadomości - odpowiedź Steve'a Jacksona - jest to absolutnie słuszne. MOP nie jest tym, co rozumie się pod pojęciem „wiadomości” w rozumieniu Ojca OO Alana Kay, który powiedział, że wielką ideą jest przesyłanie wiadomości . Co więcej, przepraszam, że już dawno wymyśliłem termin „przedmioty” w tym temacie, ponieważ wielu ludzi skupia się na mniejszym pomyśle.
radarbob,

21

Czy klasy mogą reprezentować obiekty bez bytów? Jeśli nie, dlaczego są złe / niepełne / nie koncentrują się na OOP? Czy istnieją sposoby, które należy zmienić / ulepszyć?

Krótko mówiąc, możesz zrobić wszystko, ale ten konkretny scenariusz byłby niezgodny z zasadami OOP :)

To, co opisujesz, nazywane jest czasem klasą „użytkową” - zwykle jest to znak zapachu kodu. Chcesz uniknąć tworzenia klas w celu utrzymania niektórych metod razem.

Nie każdy obiekt w twojej aplikacji musi być powiązany z prawdziwym bytem, ​​takim jak silnik lub samochód; są to obiekty biznesowe. W swojej aplikacji prawdopodobnie będziesz używać wielu swoich obiektów biznesowych, ale będziesz potrzebować nieco większej segregacji w przypadku innych operacji, które nie są częścią podmiotów biznesowych, takich jak te wymienione przez Ciebie.

Powinieneś rzucić okiem na typowe wzory architektoniczne - jednym z nich jest MVC (Model-View-Controller) .

Gdybym miał rozpowszechniać metody wymienione za pomocą MVC, oto co bym zrobił:

Wyświetl klasę:

  • GetMotorDataFromHTMLForm ()

Klasa modelu (silnik zasadniczo):

  • GetMotorManufacture ()
  • CanMotorHandleOperationConditions ()
  • CalculatePowerConsumption ()

Klasa kontrolera (MotorsController):

  • GetAllMotors ()
  • GetMotorById ()
  • GetMotorByUserRequirements ()

Wygląda na to, że używasz PHP; dobrym frameworkiem MVC do obejrzenia jest Laravel . W swoich przykładach dobrze ilustrują, do jakich metod należą.

Innym, bardziej ogólnym źródłem informacji o tym, jak zdecydować, gdzie należą metody, są zasady GRASP i SOLID .


dzięki. W gruncie rzeczy wydaje mi się, że mam klasę Controller z kilkoma domieszkami zanieczyszczeń (Model, Widok itp.). Czy to znaczy, że jeśli zmiana nazwy MotorOperations, aby MotorsControlleri oczyścić go trochę, mój zbiór funkcji będą zgodne z OOP?
Dennis

@Dennis, niekoniecznie, spójrz na moją kolekcję metod w każdej klasie. Kontroler nie jest klasą, która zawiera wszystko :) To klasa, która działa na twoich modelach i nic więcej. Jedynymi zależnościami kontrolera byłyby na ogół bezpośrednio DAL (warstwa dostępu do danych) lub usługi zapewniające dostęp do DAL. Nigdy nie chcesz uzyskiwać dostępu do widoku z kontrolera (przykład: getMotorDataFromHTMLForm), zamiast tego twój widok powinien być zależny od kontrolera.
Alexus,

2
Czy mógłbyś wyjaśnić, dlaczego Utilsklasa byłaby przykładem zapachu kodu? Ciekawe, ponieważ podobało mi się to, że losowe funkcje są zamknięte w Utilsklasie, a nie tylko samodzielne funkcje ... z mojego doświadczenia wynika, że ​​kod jest nieco bardziej czytelny, ale moje doświadczenie jest ograniczone.
HC_

3
@HC_ Posiadanie klasy Utils jest tym samym, co posiadanie folderu „Misc” w kolekcji zdjęć. Oznacza to, że byłeś leniwy, aby poprawnie przypisać swoje obiekty / potencjalnie brakujące obiekty i użyć Utils, aby to zrekompensować. Jest miejsce na klasy Util, zwłaszcza z funkcjami statycznymi i rozszerzeniami do innych klas, ale zanim utworzysz taką kolekcję, sprawdź, czy możesz włączyć je do swoich odpowiednich klas OOP :) Innym powodem jest to, że klasa może mieć tylko jedna metoda. Ale idąc dalej, musisz dodać więcej, a klasa Utils staje się większym bałaganem.
Alexus

Często kończę na bibliotece Utils LIBRARY, ale zwykle staram się grupować i nazywać swoje klasy utils nieco bardziej opisowo. Obecnie istnieje wiele bibliotek „wspólnych narzędzi” typu open source, które już mają narzędzia ogólnego przeznaczenia, których większość ludzi potrzebuje, więc rozejrzę się trochę przed napisaniem własnego.
Guy Schalnat,

15

Czy klasy mogą reprezentować obiekty bez bytów?

Mogą? Tak. Powinien? Prawdopodobnie nie - a przynajmniej nie tak, jak frazujesz rzeczy.

Obiekty faktycznie są najlepsze, gdy nie reprezentują bezpośrednio obiektu fizycznego, ponieważ rzeczywistość tak rzadko ładnie odwzorowuje kod. Ale muszą reprezentować spójną koncepcję lub obiekt kodowy. Muszą reprezentować jedną spójną odpowiedzialność.

Samo wiązanie kilku stycznie powiązanych funkcji razem to przestrzeń nazw lub moduł - a nie obiekt w języku OOP. Mogą być przydatne, ale nie są takie same i wymagają innego sposobu użycia / myślenia, aby efektywnie z nimi pracować.


3
bundling a bunch of tangentially related functions together is a namespace: to bardziej przypomina paradygmat proceduralny niż obiektowy.
Dennis

@dennis - dokładnie (lub funkcjonalny, jeśli nazwiesz go modułem). Mieszanie paradygmatów może być potężne. Lub może być strasznie niechlujny.
Telastyn

Lub oba :) - - - - -
Alexus

@Dennis: Lub żaden - łączenie tylko funkcji stycznych jest wątpliwą praktyką w każdym paradygmacie.
sdenham

Mam do czynienia z kodem, który zaczynał jako baza kodów proceduralnych. W pewnym momencie podjęto próbę przekształcenia go w OOD, ale w większości utworzono klasy w celu „przechowywania funkcji i metod”, bez faktycznego projektowania OO. Odkryłem sporo takich rzeczy, które próbują wypełnić lukę między paradygmatami, ale nie są ani w jednym, ani w drugim
Dennis

11

Klasa powinna coś wymodelować - w przeciwnym razie jest to bezcelowe. To, co jest modelowane, może nie być fizyczną „rzeczą”; zamiast tego może to być przedstawienie czegoś, co nie jest „rzeczywiste”, ale które jest potrzebne do kontrolowania modelowanego systemu. Na przykład w systemie sterowania sygnalizacją świetlną można bardzo dobrze mieć jakąś klasę ControlSignal, reprezentującą sygnał wysyłany z jednej części systemu do drugiej, wskazujący, że należy wykonać pewne działanie. W „świecie rzeczywistym” sygnały te mogą składać się z impulsów elektrycznych przekazywanych przez przewody z jednej skrzynki do drugiej. Proces modelowania czegoś, co nie jest „rzeczywiste” jako konkretny obiekt, nazywa się „reifikacją”.

Powodzenia.


Tak, prawie dokładnie tak powiedziałbym. Klasa jest niczym więcej niż modelem dla rzeczownika . Otóż ​​to. Nic dodać nic ująć. Klasa to rzeczownik, a metody to czasowniki (lub wiadomości, jeśli wolisz). Młodszy inżynier, który myśli w tych prostych terminach, może przejść długą drogę, zanim te analogie się rozpadną (w przeciwieństwie do próby udawania, że ​​klasy są opisami obiektów fizycznych - analogia, która zaczyna się rozpadać przy prawie pierwszym projekcie).
Calphool,

7

Nie. (Zredagowano tytuł, aby zadać przeciwne pytanie!)

na przykład:

Public class MyRepository
{
    public MyObject GetObject(string id)
    {
        //get data from the DB and build an object
    }
}

lub

Public class MyService
{
    public MyObject3 ProcessData(MyObject1 obj1, MyObject2 obj2)
    {
         //perform a process which is not a sole responsiblity of obj1 or obj2
    }
}

Jednak ogólnie rzecz biorąc, ideałem OOP jest odejście

public struct Car
{
    public Wheel[] Wheels;
}

public int CountWheelsOnCar(MyCarStruct car)
{
   return car.Wheels.Length;
}

do

public class Car
{
    private Wheel[] wheels;
    Public int CountWheels()
    {
        return this.wheels.Length;
    }
}

Czy masz na myśli, że mogą reprezentować obiekty bez bytów? (Zobacz komentarz, który pozostawiłem na pytanie.)
Panzercrisis,

3
Chyba zbyt długo programowałem OO - kiedy spojrzałem na MyRepository, natychmiast wyobraziłem sobie szklaną miskę na mojej komodzie z kupą monet i badziewiem. Sięgnij i weź grosz lub guzik ...
Bill K

@pan tak, podobnie jak usługa i repozytorium w moim przykładzie
Ewan

@bill you crazy old głupi !!! To jest klasa MyButtonAndOrPennyBowl! czyste kodowanie ftw
Ewan

1
Twój drugi przykład wygląda mi na funkcję przebraną za przedmiot, która nie jest (moim zdaniem) uzasadniona sama w sobie, choć może istnieć inne uzasadnienie (np. Jeśli funkcje nie są jednostkami pierwszej klasy w języku). )
sdenham,

5

Myślę, że wizualizacja czegoś w prawdziwym świecie jest pomocna podczas kodowania klas, ale nie jest konieczna.

W rzeczywistości, w zależności od tego, jak dosłownie chcesz być, wiele obiektów, z którymi pracujemy, w ogóle nie ma fizycznych reprezentacji. Na przykład - rozważ architekturę MVC. W prawdziwym świecie nie ma modelu ani kontrolera, mimo że generalnie są reprezentowane przez klasy. Te trzy razem często reprezentują coś, ale nie zawsze - ale, jak powiedziałem, prawdopodobnie możesz wymusić dopasowanie do czegoś, jeśli naprawdę chcesz (i wyobrażenie sobie, że COŚ pomaga! Wizualizuję większość obiektów w jakiś sposób - po prostu nic widziałbyś kiedykolwiek w prawdziwym świecie).

Przeważnie te „Zasady”, których dowiesz się o OO, są tylko wskazówkami mającymi na celu nakierowanie Cię na myślenie w OO niekoniecznie o rzeczy, o które martwisz się, gdy używasz go do codziennego pisania kodu.

Nawiasem mówiąc, OO sam w sobie nie jest jakimś panaceum i nie pomaga ci wcale podczas pierwszego przejścia do kodowania jakiegoś rozwiązania, ale myślę, że jeśli zrobione dobrze, to naprawdę fantastyczny sposób na uporządkowanie kodu, aby mógł być bardziej łatwo zrozumiałe później. Pisanie łatwego do utrzymania kodu jest prawdopodobnie jednym z najtrudniejszych zadań w rozwoju oprogramowania iw wielu przypadkach (wszystko, co wymaga ciągłego debugowania / konserwacji) jest zdecydowanie najważniejsze.


5

Czy obiekt musi reprezentować byt?

Pytanie: Który podmiot Loggerreprezentuje?

Nie metaforycznie - dosłownie.

Wyjaśniając studentom OOP, pomocne jest wyjaśnienie obiektów o analogiach do świata fizycznego.

Alan Kay - jeden z ojców OOP - napisał:

[...]

Jego pierwotna koncepcja składała się z następujących części.

  • Myślałem o przedmiotach będących jak komórki biologiczne i / lub pojedyncze komputery w sieci, zdolne do komunikowania się tylko z wiadomościami
  • Chciałem pozbyć się danych.

[...]

OOP oznacza dla mnie tylko przesyłanie wiadomości, lokalne przechowywanie i ochronę oraz

ukrywanie procesu państwowego i ekstremalne późne wiązanie wszystkich rzeczy.

prawie niewiarygodna architektura HW. Zrozumiałem, że

metafora komórka / cały komputer pozbyłaby się danych

źródło

Z tego obiekty najlepiej rozumieć jako

  • obiekty autarkiczne enkapsulujące / ukrywające dane

  • komunikowanie się z innymi obiektami za pomocą wiadomości

Czy klasy mogą reprezentować obiekty bez bytów?

Zdecydowanie: Pomyśl o tym Math


Jeśli chodzi o twój przykład:

Przykład: czy klasę można nazwać MotorOperations lub MotorActions, gdzie nie ma encji, ale metody wewnątrz klasy robią takie rzeczy jak

  • getMotorDataFromHTMLForm ()

  • getMotorManufacts ()

  • selectMotorFromUserRequirements (wymagania $)

  • canMotorCanHandleOperatingConditions (warunki $)

  • computePowerConsumptionForMotor ($ id)

Aby zdecydować, gdzie umieścić te metody, musisz spojrzeć na responsibilities: kto jest odpowiedzialny za co .

getMotorDataFromHTMLForm ()

Kontekstem takiej metody byłoby zbudowanie obiektu motorycznego . Silnik nie jest odpowiedzialny za tworzenie się na podstawie danych pobranych za pośrednictwem formularza . W grę wchodzą co najmniej dwa przedmioty; jeden jest silnikiem, a drugi twórcą silnika .

getMotorManufacts ()

Typowy kontekst, w którym można by napisać taki sposób jest service.

selectMotorFromUserRequirements (wymagania $)

Byłoby to również użyte w servicekontekście

canMotorCanHandleOperatingConditions (warunki $)

To jest pytanie do motorobiektu

computePowerConsumptionForMotor ($ id)

To też pytanie najlepiej zadać sam silnik.


tl; dr

Metafora objectsjak fizycznie obiektów jest bardziej irytujące niż pomocne.


wow twoja odpowiedź tchnie życie w OOP! Muszę powiedzieć, że nie miałem na myśli fizycznego końca tego wszystkiego. celem mojego pytania było bardziej „czy obiekt musi być thingz danymi, w których dane wyraźnie należą do rzeczy i funkcje, które wyraźnie działają na danych, które należą do rzeczy”. Logger w tym przypadku, choć nie jest rzeczą fizyczną, jest pojęciem podobnym do „fizycznego dziennika”. Czy posiada dane, które są rdzeniem do jej stanu, a nie jest tylko przejściowy do niego, że może polegać na realizacji i interpretacji .. i jest bardziej więc moje pytanie, gdzie się dzieje ..
Dennis

ale tak, odpowiedzi musiały dotyczyć mojego fizycznego uprzedzenia
Dennis

3

Tak, możesz to zrobić. Ale zasadniczo tworzysz klasę, która zapewnia taką samą funkcjonalność jak biblioteka proceduralna. Jedynym powodem jest to, że w twoim języku brakuje modułów proceduralnych (np. Java lub Ruby).

W języku z modułami proceduralnymi (myślę, że PHP ma moduły proceduralne), możesz rozważyć użycie modułu proceduralnego.

Możesz również rozważyć przeprojektowanie swojej klasy, aby instancja klasy reprezentowała spójny obiekt.

Ale używaj notacji OO tylko wtedy, gdy daje ci ona dodatkową moc, nie tylko ze względu na bycie OO!


3

Słowami laika

  • To, co opisujesz, nazywa się klasą użyteczności.
  • Nie ma stanu, co oznacza, że ​​nigdy nie będziesz musiał mieć kilku jego wystąpień
  • Wszystkie metody są statyczne, co oznacza, że ​​musisz przekazać wszystko jako parametry

Takie klasy istnieją, na przykład Java SDK ma klasę Collections, która składa się wyłącznie z metod statycznych, które działają na kolekcjach lub zwracają kolekcje.

Odpowiedź brzmiałaby: nie, nie wszystkie klasy muszą być modelowane z encji domeny.

Z drugiej strony, takich klas jest tylko kilka lub powinno być tylko kilka w programie wykonanym w języku OOP, ponieważ prawdziwa moc OOP polega na polimorfizmie i enkapsulacji.

To tak, jakbyś podróżował samolotem z miejsca na miejsce, nie latając, lecz jeżdżąc autostradą. Samoloty mają koła jak samochody, ale są przeznaczone do latania.


2

Nie, klasa reprezentuje jedynie coś, co można utworzyć, ma członków i może być dziedziczone.

W rzeczywistości Twój język może mieć klasy statyczne, które nie są tworzone nawet kilka razy.

.NETMath to świetny przykład „profesjonalnej” klasy, która nie reprezentuje żadnego bytu (chyba że chcesz filozoficznie zrozumieć, czym jest matematyka ...), a także ilustruje uzasadniony przypadek użycia takiej klasy. Ma tylko metody i 2 pola (oba reprezentują indywidualne stałe).

Hierarchia klas podobnej biblioteki Math.Netgrupuje metody matematyczne / numeryczne w klasy według typu. Tutaj klasy reprezentują nie byt, ale logiczną kategorię.

Sam często kończę tworzenie (statycznych) klas, które są niczym więcej niż zbiorem powiązanych (statycznych) funkcji lub grupą stałych wygodnie pogrupowanych w jednym centralnym miejscu. Nie twierdziłbym, że to dobry projekt, ale czasem jest to najprostsze rozwiązanie.


1
Fakt, że metody matematyczne są umieszczone w .NET / BCL w osobnej klasie jako metody statyczne, nie jest koniecznością ani rozważaniem projektowym, ale konsekwencją faktu, że w C # nie istnieją metody wolnostojące. W C ++ takie funkcje można po prostu pogrupować w przestrzeń nazw.
Vlad

1

Odpowiedzi na twoje pytania ostatecznie zależą od tego, jak dokładnie zdefiniowane są terminy takie jak „klasa” i „byt”. Wykonałeś dobrą robotę, definiując to drugie, dopuszczając zarówno fizyczne, jak i koncepcyjne byty. Ale termin „klasa” dla purystów zawsze będzie „fabryką do tworzenia instancji obiektów o szczególnej wewnętrznej reprezentacji”, a dla pragmatyków termin ten będzie obejmował rzeczy Java lub C ++ pogardzane przez purystów. To samo dotyczy terminu „OOP”, co pragmatycy mogliby powiedzieć, że robią to Java i C ++, ale który purysta miałby znaczyć to, co Alan Kay miał na myśli, gdy zauważył [„Wynalazłem termin zorientowany obiektowo i mogę powiedzieć, że nie mieć na myśli C ++ ”] ( Co więc * naprawdę * Alan Kay miał na myśli, mówiąc„ obiektowo ”? ).

Jeśli przyjrzysz się pragmatystycznemu poglądowi, możesz zaakceptować klasy narzędziowe bez instancji. Ale purystyczny pogląd jest bardziej interesujący. OOP, według Kay, zawsze bardziej dotyczyła wiadomości niż klas. Więc na twoje pytania:

Czy klasy mogą reprezentować obiekty bez bytów?

Nie. Klasy klasyfikują obiekty. Klasy są z definicji jednostkami, do których wysyłasz wiadomość, na przykład w newcelu wytworzenia obiektu. Obiekt jest bytem wykonanym z klasy. Istnieją klasy służące do wytwarzania i klasyfikacji przedmiotów. Tak robią klasy. Klasy tworzą przedmioty. Używamy klas do klasyfikowania obiektów. Więc jeśli C jest tylko pakietem metod, które nie pozwalają na tworzenie instancji lub podklasowanie, nie może być żadnych obiektów sklasyfikowanych przez C, więc C nie jest klasą.

Jeśli nie, dlaczego są złe / niepełne / nie koncentrują się na OOP?

Nie są źli. Tylko nie nazywaj ich klasami. Pakiet metod to OOPable: coś, do czego można wysłać wiadomość w celu wywołania metody, ale nie jest to klasa, chyba że może utworzyć instancję obiektu. Czy znasz Ruby? W Rubim moduł jest pakietem metod. Klasa jest modułem, który może wystąpień obiektów. W module nie ma nic złego . Ale rzeczą, która odróżnia klasę od modułu (w kategoriach czystego OOP) jest to, że klasa może mieć instancje. Moduł to tylko niektóre metody. Pomyłką jest to, że C ++, Java i inne języki używają terminu „klasa” zarówno dla klasy, jak i modułu .

Teraz, aby spojrzeć na jeden ze swoich konkretnych przykładów, pytasz o MotorOperationsklasę, do której możesz wysłać wiadomość computePowerConsumptionForMotorz argumentem id. Czy to złe? Przynajmniej nie narusza to zasady Tell Don't Ask . Czy możemy mieć do klasy silnik i wysłać mu powerConsumptionwiadomość? Może nie w 100% przypadków, ale może próba zrobienia takich rzeczy doprowadzi do ciekawych informacji na temat twojego kodu. Lub może prowadzić do eksplozji małych klas, co byłoby złe.

Czy istnieją sposoby, które należy zmienić / ulepszyć koncepcyjnie, aby były zgodne z OOP?

Jeśli „wykonywanie OOP” jest dla Ciebie ważne, powinieneś poszukać sposobów na architekturę systemu w komponenty, które komunikują się, wysyłając do siebie wiadomości. To jest właśnie to, co OOP jest , albo przynajmniej co fałszerz pieniędzy terminu miał na myśli. Klasy narzędzi nie są OOP w tym widoku. Ale dla niektórych mogą być.

Próba stworzenia całego dużego systemu z milionów żywych, oddychających obiektów, z których wszystkie powstały w wyniku zajęć, może działać w przypadku niektórych projektów. Ale jeśli odkryjesz, że tworzysz sztuczne, źle brzmiące klasy, należy wprowadzić moduły. Staraj się podkreślać klasy i używaj modułów, gdy możliwe do odtworzenia klasy byłyby śmieszne.

TL; DR - pakiety metod nie zawsze są złe. Najpierw spróbuj użyć klas, które można utworzyć. Wróć do „modułów” tylko w razie potrzeby.


0

Biorąc podane przykłady:

getMotorDataFromHTMLForm()
selectMotorFromUserRequirements($requirements)

Wyglądają jak metody „fabryczne”, które zwracałyby Motorobiekt. Drugi oznacza, że ​​albo tworzysz nowy obiekt w celu spełnienia wymagań, albo masz bazę danych lub kolekcję silników w pamięci, które sprawdzasz. W takim przypadku powinna to być metoda. Lub może to być metoda obiektu wymagań.

getMotorManufacturers()

Skąd je bierzesz? To właśnie powinna być metoda.

canMotorCanHandleOperatingConditions($conditions)
computePowerConsumptionForMotor($id)

Wyglądają, jakby to były metody Motor.


Tak. jest to „pakiet prawdopodobnie niepowiązanych metod” (w skrócie BOPUM). Zgadzam się z komentarzami Factory i Motor. getMotorManufacturersjest zwrócenie wszystkich producentów silników z bazy danych. Nie jestem pewien, dokąd to idzie. Zajmie mi trochę czasu, aby rozwikłać ten BOPUM, aby umieścić rzeczy tam, gdzie muszą iść ...
Dennis

Otrzymuję getMotorManufacturersz bazy danych. Baza danych nie może mieć metody ... Obecnie mam wzorzec DataMapper, który wysyła zapytanie do bazy danych, inicjuje tablicę i zapełnia ją obiektami motorycznymi (zawierającymi również informacje o producencie), a następnie zwraca tę tablicę wywołującemu. Dzwoniącym jest moja MotorOperationsklasa, która z kolei jest wywoływana z ProductSelectionklasy (która zawiera algorytm używany do wybierania Silników, a załadowane informacje o silniku to dane dla tego algorytmu)
Dennis

0

Obiekt to zbiór metod i danych o wysokiej spójności. Należą do klasy, ponieważ są ze sobą ściśle powiązane, a stan zostaje zachowany.

Dzieje się tak niezależnie od tego, czy używasz dużego projektu z góry i próbujesz modelować wszystko, czy też wschodzącego projektu, w którym iterujesz i ewoluujesz obiekt w dowolny sposób odpowiadający potrzebom systemu w danym czasie.

Jeśli nie masz powodu do zachowania stanu, prawdopodobnie nie masz żadnego powodu do tworzenia instancji obiektu, co oznacza, że ​​prawdopodobnie nie ma powodu, aby mieć klasę. O ile język, którego używasz, nie ma możliwości zdefiniowania przestrzeni nazw innej niż użycie klasy. W którym używanie klasy powinno być w porządku, ponieważ byłoby idiomatyczne.

Nie mogę wymyślić żadnych negatywnych aspektów używania klas w ten sposób, poza typowymi. Zapraszanie niepotrzebnych kosztów i złożoności poprzez konieczność utworzenia „przestrzeni nazw”. Każdy, kto obsługuje ten kod, zastanawia się, gdzie dane kosztują dodatkowe obciążenie poznawcze (najprawdopodobniej jednorazowy koszt na osobę). To niezwykłe zastosowanie bez dodatkowej wartości.

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.