Jak wybrać pomiędzy metodami statycznymi i niestatycznymi?

[Edytuj]

Moje pierwotne pytanie brzmiało: "dlaczego decydować między statycznymi a niestatycznymi? Oboje robią to samo..."

Niestety został edytowany do pytania C#, czego tak naprawdę chciałem uniknąć.

Więc pozwól mi zrobić kilka dodatków:

Kiedy mówię interfejs, nie mam na myśli C# - keyword-interface, ale co rozumiem coś w rodzaju interfejsu C++: Zestaw dobrze zdefiniowanych funkcji do pracy z moim obiektem. Mówiąc o moim interfejsie, mam na myśli, że mam różne funkcje (statyczne/niestatyczne), które robią to samo. Mój interfejs nie jest już dobrze zdefiniowany, gdy istnieją różne funkcje, które robią to samo.

Więc, jak pisał Bob Woźny, mogę zaimplementować funkcję Validate ()

Document.Validate(myDocumentObject);    

Ale także

myConcreteDocumentObject.Validate();

To get back to my Copy () - przykład można zaimplementować Copy () jak

myConcreteDocument.Copy(toPath);

Ale także

Document.Copy(myConcreteDocumentObject, toPath)

Lub

Document.Copy(fromPath, toPath)

Kiedy myślę o folderze, który zawiera wszystkie pliki należące do mojego Dokument (w tym przypadku nie jestem zależny od konkretnej instancji - ale jestem zależny od innych rzeczy :)).

Ogólnie mówię o metodach statycznych, a nie klasach statycznych (sorry, if I forgot to mension).

Ale jak powiedział Anton Gogolev, myślę, że moja klasa dokumentów nie jest dobrym przykładem i nie jest dobrze zaprojektowana, więc myślę, że będę musiał spojrzeć na zasadę jednej odpowiedzialności.

Mógłbym również zaimplementować jakiś rodzaj ManagerClass, który działa z moim DocumentClass:

Na przykład:

myDocumentManagerObject.Copy(myConcreteDocumentObject, toPath);

Lub

myDocumentManagerObject.Copy(myConcreteDocumentObject, toPath);

Ale jeśli odwołuję się do podejścia 1), chciałbym tworzyć obiekty, które wykonują swoje zadania samodzielnie, a nie inne obiekty (DocumentManager), które robią coś Z moim DocumentObject.

(mam nadzieję, że nie będzie to obrać kierunku religijnej dyskusji o OOP ;).)

[/edytuj]


Stara Wersja:

Na początku wydaje się to być bardzo podstawowe pytanie, jak "kiedy używać metod statycznych, a kiedy nie" ale to jest coś, z czym mam do czynienia od czasu do czasu (i mam trudności z opisaniem, na czym polega prawdziwy problem; być może chodzi o to, aby uzyskać powody, dla których (nie) używać 1) lub dlaczego (nie) używać 2)).

Nie jest to jednak żaden problem, ponieważ nie jest to problem z C#-restricted.]}

W OOP istnieją dwa podejścia (m.in.) do pracy z obiektami:

1) Jeśli chcę, aby mój obiekt coś zrobił, po prostu mówię mu, aby zrobił więc:

myConcreteObject.DoSomething();
To jak rozmowa z przedmiotem.

2) lub jeśli jesteś fanem metod statycznych:

ObjectClass.JustDoIt();

W jakiś sposób myślę, że funkcje statyczne po prostu "czują się" lepiej. Dlatego często używam metod statycznych (być niezależnym od konkretnej instancji - niezależność jest zawsze dobra).

Tak więc, projektując klasę często muszę zdecydować, czy zastosuję podejście 1) czy podejście 2): {]}

Wyobraź sobie, że masz klasę "Document", która powinna oznaczać dokument, który powinien być zapisany w bazie danych:

Dokument

  • składa się z jednego lub więcej plików graficznych z systemu plików (stają się one pojedynczymi stronami dokumentu)
  • ma coś w rodzaju bibliografii-pola, do których użytkownik może dodać informacje o dokumencie-który jest zapisywany do dodatkowego pliku
  • i powinny mieć pewne operacje, takie jak Copy (), AddPage (), RemovePage() itp.

Teraz mam do czynienia z kilkoma sposobami tworzenia tego Klasa:

//----- 1) non static approach/talking to objects -----
Document newDocument = new Document();

// Copy document to x (another database, for example)
newDocument.Copy(toPath);

Podoba mi się to: każę dokumentowi skopiować się do bazy danych x, a obiekt robi to sam. Nieźle.

//----- 2) static approach ----------------------------
Document.Copy(myDocumentObject, toPath);
Dlaczego nie? Również miły, czuje się bardzo poręczny...

Więc, który z nich wdrożyć? Jedno i drugie? A może statyczne podejście do klasy pomocnika? Lub wybierz podejście 1) i trzymać się go, aby nie osłabić interfejsu mojej klasy dokumentów?

Myśląc o obu podejściach dochodzę do wniosku ,że (teoretycznie) można by wdrożyć Dowolna funkcja jako funkcja statyczna:

Class.Function(aConcreteClassObject, parameters);

Ale także nie statyczne:

aConcreteObject.DoSomething(parameters);

Aby dać przykład z prawdziwego świata:

[EDIT (dodany parametr"Sorry, I forgot")]

//----- 2) static approach ----------------------------
File.Copy(fromPath, toPath);    // .Net-Framework-like

[/edytuj]

Ale także:

//----- 1) non static approach ------------------------
ExampeFileClass fileObject = new ExampleFileClass();
fileObject.Copy(toPath);

Lub nawet (rodzaj OOP-Overkill):

//----- 1) non static approach, too -------------------
fileObject.ToPath = @"C:\Test\file.txt";     // property of fileObject
fileObject.Copy();                           // copy to toPath

Dlaczego (nie) używać 1) lub dlaczego (nie) używać 2)?

(nie koncentrowałbym się zbytnio na przykładzie klasy Document, ponieważ jest to bardziej ogólne Pytanie o dobrą klasę design.)

Author: Inno, 2009-04-28

11 answers

Pocałunek. Jeśli nie trzeba dzwonić do konstruktora, to jeszcze lepiej.

Również metoda statyczna powinna ci trochę powiedzieć o tym, jak działa funkcja:

  • nie działa na zmiennych poza tym, co jest do niego przekazywane.
  • nie wymaga żadnej pamięci poza wywołaniem metody (nie licząc tego, co zostanie zwrócone z funkcji)

Są jeszcze inne ważne rzeczy do odnotowania:

  • statyczne metody w niektórych przypadkach (Java) to nie mogą być overridden/subclassed, więc lepiej nadają się do przypadków, w których wdrożenie nie będzie wymagało zmian.
  • niektórzy twierdzą, że metody statyczne są z natury trudne do przetestowania .

Chciałbym również odnieść się do tego wątku i prostej wyszukiwarki google, która szczerze mówiąc dostarcza sporej ilości dyskusji na ten temat.

 8
Author: cgp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:45:36

Zaczynamy.

Po pierwsze:

Więc często używam metod statycznych (być niezależnym od konkretnej instancji-niezależność jest zawsze dobra).

Wręcz przeciwnie: używając metod statycznych jesteś bardzo zależny od konkretnej instancji.

Jeśli chodzi o Twoje zdanie, nie poszłabym w żadną stronę. Wymieniłeś wszystkie zadania klasy Document, która obejmuje agregację danych, zapisywanie się do bazy danych oraz operacje na stron i kopiowanie. To za dużo. Na SRP , każdy "moduł" (tutaj "moduł" używany jako termin catch-all) powinien mieć tylko jeden powód do zmiany. Twoja Document ma wiele obowiązków, stąd ma całą masę powodów do zmiany. To nie jest dobre. Mając to na uwadze, przeniosłbym całą logikę na inne klasy o ściśle określonych obowiązkach. Mniej lub bardziej przyjęte kryterium tego, co przenieść, zostało wprowadzone, jak sądzę, przez Herb Sutter lub Andrei Alexandrescu, an jest następujący: wszystkie operacje (metody myślowe), które mogą być wykonane z obiektem w ramach jego zamówienia publicznego, powinny być przeniesione poza przedmiot, o którym mowa.
 16
Author: Anton Gogolev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 13:58:01

Nie można używać metod statycznych do implementacji interfejsu i nie można nadpisywać metod statycznych. Więc używanie metod statycznych oznacza, że po prostu nie robisz OOP.

Zastanów się, jak zaimplementowałbyś następującą funkcjonalność używając tylko metod statycznych?

interface IDocument 
{
   void Print(IDevice targetDevice);
}

IDocument instance;

instance = new PdfDocument();
instance.Print(printer);

instance = new WordDocument();
instance.Print(printer);
 9
Author: Groo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 14:53:15

Moja "reguła" to:

  • Jeśli nie muszę używać właściwości z mojej klasy, zrób to statycznie. (innymi słowy, jeśli metoda nie jest tak naprawdę dołączona do klasy, tylko do asocjacji logicznej, Użyj static)
 6
Author: Sergio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 13:54:10

Ogólnie jeśli masz metodę jak:

Document.Copy(myDocumentObject, toPath);

Myślę, że lepiej jest użyć metody niestatycznej, ponieważ pierwszy parametr będący dokumentem sugeruje, że jest to naprawdę operacja na dokumencie.

 3
Author: Grzenio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 13:54:42

Ogólnie rzecz biorąc, podczas programowania przy użyciu oo, będziesz chciał unikać używania metod statycznych. W OOP, ideą jest reprezentowanie wszystkiego jako obiektów i dać każdemu obiektowi jasny zestaw umiejętności, które reprezentują jego podstawową abstrakcję. Metody statyczne "przełamują" tę abstrakcję.

Twój przykład mówiący o klasie dokumentu z metodą kopiowania jest najlepszym przykładem. Argumentowałbym, że poprawna implementacja OO jest pierwszą drogą . Czyli mieć kopię jako przykładowa Metoda:

document1.copy(toPath)

Ma sens, że możliwość kopiowania jest częścią abstrakcji rdzenia dokumentów. W ten sposób kod klienta wysyłającego wiadomość copy musi tylko określić, gdzie skopiować do , ponieważ zrozumiałe jest, że dokument śledzi, gdzie znajduje się wewnętrznie. Nie ma potrzeby, aby te informacje były powielane gdziekolwiek indziej, co jest poważnym problemem z trzecią opcją, którą prezentujesz, która wygląda tak:

Document.copy(fromPath, toPath)
 2
Author: Nick Stamas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-13 19:42:50

Jeśli musisz pytać, nie używaj statyki.

Rzeczywista zasada (i jest wiele prawdziwych powodów technicznych, ale uważam, że pomaga to wyjaśnić pojęcia):

  • Jeśli dana klasa może istnieć wiele razy, nie jest statyczna.

  • Jeśli dana metoda działa przeciwko informacji o instancji, nie jest statyczna.

  • Jeśli metoda lub klasa dotyczy meta-informacji, to jest statyczna.

Z tymi wytycznymi to jasne, że pliki i dokumenty są wielokrotnościami, a kopiowanie jest działaniem przeciwko instancji. Metoda nie powinna być statyczna.

 1
Author: annakata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 14:08:39

Metody statyczne mogą być bardzo przydatne, uwielbiam metody rozszerzania, ale wymuszają sprzęganie i jeśli są używane niewłaściwie, mogą sprawić, że testowanie stanie się koszmarem!

Dobrym przykładem kiedy używać statycznego jest kiedy chcesz to zrobić Walidacja

public static errors Validate(Document myDoc)
{
..some validation code
}

To jest bardzo testowalne i nie ma znaczenia, że Twoje ścisłe powiązanie metody z obiektem. Złym miejscem do korzystania z metody statycznej jest, gdy dozuje coś innego, a następnie po prostu coś zwraca, przykładem może być w warstwie Biz, która waliduje obiekt i jeśli przejdzie walidację, zapisze dane do DB

public static errors ValidateAndSave(Document myDoc)
{
    errors docErrors = Validate(myDoc);
    if(docErrors.count==0)
    {
         docErrors = SaveToDB(myDoc);
    }

   return docErrors; 
} 

To jest prawdziwy ból do testowania, ponieważ za każdym razem, gdy go uruchomić, i przechodzi walidacji biorąc do bazy danych, twoja logika Biz może nie generować błąd, ale twoja warstwa DAL może, więc zamiast tylko testowania funkcjonalności warstwy Biz również trzeba przetestować warstwę DAL, jak również, i szczelnie łącząc swój obiekt, warstwy Biz i twój Dal razem czyni to bardzo trudne do testowania i utrzymania.

 1
Author: Bob The Janitor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 15:23:31

Ogólnie rzecz biorąc, powiedziałbym, że "kopiowanie" siebie, jeśli chodzi o obiekt, zwykle oznacza klonowanie własnych danych w nowy obiekt. Opisane tutaj "kopiowanie" jest czymś, co system plików robi w Twoim imieniu, a nie obiekt. Jako taki, zrobiłbym to metodą statyczną, a nie metodą na instancji dokumentu.

 0
Author: mquander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 13:54:54

To samo co altCongnito i dodam ten fileObject.Kopiuj każdy będzie używał, więcej niż obiekt fileObject. Statyczne dla funkcji, które mają idealną relację z klasą, A nie funkcjonalną jej zależność.

 0
Author: Chocolim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 13:56:46

Jeśli używasz innych obiektów, to domyślnie używasz metod poziomu instancji, aby można było skonfigurować te zależności za pomocą iniekcji zależności.

Na przykład, jeśli jeden z tych obrazów był obrazem SVG, możesz mieć zależność od parsera XML, który (przynajmniej w Javie) ma wiele implementacji, podobnie jak w przypadku RENDERERÓW SVG, jak sobie wyobrażam, i wiele innych składowych typów obrazów może wymagać podobnych rozwiązań, które ewoluują w miarę ewolucji stanu obiektu lub które muszą być zmiany w różnych scenariuszach użytkowania (np. test, produkcja, różne projekty ponownie wykorzystujące kod).

Migające pomarańczowe światło ostrzegawcze oznacza, że możesz używać klas, które nie są częścią domyślnych bibliotek twojego frameworka, więc dokonałeś wyboru zewnętrznego komponentu i jeśli używasz statyki, nie jesteś w stanie zmodyfikować tej decyzji.

Użytecznym "redline" jest to, że jeśli dotkniesz innego procesu (serwer bazy danych, serwis internetowy itp.), to uznałbym statyczną metodę za złą 100% czasu, ponieważ sprawia to, że testy jednostkowe są bardziej trudne.

 0
Author: Simon Gibbs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-29 13:13:37