2009-04-06 10 views
6

Czy zawsze należy utworzyć interfejs, jeśli istnieje możliwość, że może być coś innego, co mogłoby go użyć, lub poczekać, aż pojawi się rzeczywiste zapotrzebowanie, a następnie zastosować refaktor?Czy należy utworzyć interfejs, kiedy (obecnie) będzie tylko jedna klasa, która go implementuje?

Programowanie do interfejsu wydaje się generalnie jak radą dźwięku, ale wtedy nie YAGNI ...

myślę, może to zależy od sytuacji. W tej chwili mam obiekt reprezentujący folder, który może zawierać przepisy lub inne foldery. Zamiast korzystać bezpośrednio z Folder, czy powinienem się martwić o wdrożenie czegoś takiego jak IContainer? W przypadku, gdy w przyszłości chcę mieć przepis, który odwołuje się do innych receptur podrzędnych (na przykład przepis na szarlotkę, który jest również pojemnikiem na recepturę skórki pierożków):

Odpowiedz

8

To zawsze zależy od sytuacji. Jeśli wiesz, że będzie inna klasa za pomocą interfejsu, to tak, utwórz klasę interfejsu, aby zaoszczędzić czas później. Jednakże, jeśli nie jesteś pewien (i przez większość czasu nie jesteś), poczekaj, aż go potrzebujesz.

Teraz nie oznacza to ignorowania możliwości interfejsu - pomyśl o publicznych metodach obiektu i takich, których celem jest później tworzenie interfejsu, ale nie zamazyjmy kodu źródłowego czegokolwiek, czego tak naprawdę nie robisz POTRZEBA.

+0

YAGNI, nie będziesz go potrzebować -> nie będziesz tego potrzebować –

+1

Dokładnie. Za każdym razem, gdy wprowadzałem interfejsy lub cokolwiek "na wszelki wypadek", okazało się, że nigdy nie potrzebowali tego. Ale twój przebieg może się różnić. –

2

Powiedziałbym, że to zależy bardziej od tego, ile miejsc zamierzasz użyć klasy, a mniej na ile klas może ewentualnie zaimplementować interfejs. Jeśli korzystasz tylko z Folderu w jednym lub dwóch miejscach, powiedziałbym, że poczekaj, aż pojawi się rzeczywiste zapotrzebowanie na interfejs, zanim zaimplementujesz go i zmienisz. Jeśli jednak Folder będzie używany w 100 różnych miejscach, możesz zaoszczędzić trochę czasu, programując do interfejsu z przodu.

3

Zawsze będzie test, który go użyje, prawda (robisz testy jednostkowe, prawda?). Co oznacza, że ​​są to zawsze klasy N + 1, które go używają, gdzie N to liczba klas, które używają twojej klasy w aplikacji.

Innym celem interfejsu oprócz iniekcji zależności jest oddzielenie problemu, tak aby klasa mogła w rzeczywistości zaimplementować wiele interfejsów.

Miej to wszystko na uwadze, ale zawsze możesz mieć interfejs (y) wprowadzony później poprzez refaktoryzację, jeśli nie zostanie zaimplementowany na początku.

+0

Co się stanie, jeśli klasa jest na tyle prosta, że ​​próbny obiekt nie jest potrzebny do testowania jednostkowego (tj. Jest wystarczająco prosty, aby użyć prawdziwego obiektu)? – Davy8

+0

Nigdy nie powiedziałem nic o próbnych obiektach, czy ja nie :-)? Mówię tylko, że liczba klas, które go używają to zawsze + 1 (test). Zgadzam się, że interfejsy można wprowadzić później przez proste refaktoryzowanie. – topchef

+0

Ah, źle odczytałem, "używa", a nie "implementuje" – Davy8

2

Generalnie nie powinieneś zajmować się tworzeniem interfejsu, jeśli tylko jedna klasa go wdroży, nawet jeśli przewidujesz dla niego możliwą klasę, ponieważ mogą wystąpić problemy z implementacją, które nie pojawią się, dopóki klasa nie zostanie faktycznie przetestowane w scenariuszu, w którym to przypadku interfejs utworzony przedwcześnie może mieć zbyt wiele memów lub może brakować członka.

Na przykład zespół biblioteki .NET Framework Bas Class przyznał się do przedwczesnego zaprojektowania ICollection, gdy zawierał właściwość SyncRoot. Dla późniejszego generycznego ICollection<T> zdecydowali się go usunąć (http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx).

Jeśli masz zamiar stworzyć fałszywy obiekt implementujący ten sam interfejs, to będzie on liczony jako druga implementacja, która usprawiedliwia tworzenie inteface. Jednak nie wszystkie testy jednostkowe gwarantują pozorny interfejs.

2

Pomyśl o interfejsie jako umowie definiującej semantykę lub koncepcję. To podejście ogólne, a nie specyficzne dla języka.W kontekście OO, jeśli pracujesz w pojedynczym modelu dziedziczenia, istnieje doskonałe uzasadnienie dla preferowania interfejsów ponad klasami w celu zdefiniowania modelu obiektu, ponieważ ta pojedyncza ścieżka klasy super jest bardzo cenna i chcesz ją zapisać dla coś bardziej "istotnego" niż definiowanie właściwości, które są eksponowane na obiekcie lub metodach.

Posiadanie semantyki IContainer (umowy) jest dość kiepskim powodem, aby utworzyć interfejs z folderu; lepiej mieć swój folder (jeśli robi on jakąś nie banalną logikę) "implementować" (prawdopodobnie już istniejący) interfejs IContainer lub ICollection w podstawowych frameworkach językowych.

Jak zawsze, lepszy wybór zależy od konkretnego problemu. W przypadku twoich przepisów, które są również folderami (?!), Prawdopodobnie myślisz o rodzic-dziecko lub składzie, związku - semantyce, która może (i powinna) być wyrażona za pomocą interfejsów, jeśli będziesz mieć inne elementy w swoim systemie "działać" na rzeczach, które składają się z tego rodzaju semantyki.

Jest trochę nad głową (programowanie) z interfejsami, a jeśli znajdziesz się, gdy skończysz z niczym więcej niż zestawem klas i interfejsów Woof i IWoof, będziesz wiedział, że prawdopodobnie nie zrobiłeś tego ". Trzeba wyrazić swój problem w kategoriach interfejsów - proste klasy byłyby wystarczające.

Z reguły dla każdego I powinieneś mieć co najmniej kilka konkretnych klas (z bardziej znaczącymi nazwami innymi niż IImpl, lub).

Nadzieję, że pomaga.

+0

Ta rzecz zjadła moje kątowe nawiasy: dla każdego Ixxx ... imiona inne niż IxxxImpl lub XXX. – alphazero

+1

W ten sposób konwertuje ustawione pod kątem '<' '>' nawiasy tak, jakby były w stylu HTML. Aby tego uniknąć, użyj backticksów wokół postaci, –

1

Wiele osób już przedstawiło bardzo dobre porady. Jedną z rzeczy, które chciałbym dodać, jest to, że jeśli chcesz uniknąć bezpośrednich trudnych zależności na konkretnych klasach, interfejsy pomogą w zapewnieniu luźnego sprzężenia. Jeśli tworzysz architekturę opartą na wtyczkach, to interfejsy są zdecydowanie najlepszym rozwiązaniem. Jeśli masz zamiar pisać testy jednostkowe obok siebie lub w późniejszym wierszu, prawdopodobnie zauważysz, że kod, który wywołuje twoją klasę folderów, będzie musiał nosić konkretną implementację, aby kod wywołania mógł być testowalny. . Jeśli twoja konkretna implementacja klasy folderów będzie z kolei rozmawiać z DB lub usługą, będziesz musiał to również przenieść do testów, co bardzo szybko stanie się nieporęczne. Tylko moje 2 centy.

Powiązane problemy