Nasza dziedzina wiedzy obejmuje osoby chodzące boso po płycie rejestrującej ciśnienie. Dokonujemy rozpoznawania obrazu, co powoduje powstanie obiektów klasy „Foot”, jeśli ludzka stopa zostanie rozpoznana w danych czujnika.
Istnieje kilka obliczeń, które należy wykonać na danych stopy.
Teraz, który interfejs API byłby lepszy:
class Foot : public RecognizedObject {
MaxPressureFrame getMaxPressureFrame();
FootAxis getFootAxis();
AnatomicalZones getAnatomicalZones();
// + similar getters for other calculations
// ...
}
Lub:
class Foot : public RecognizedObject {
virtual CalculationBase getCalculation(QString aName);
// ...
}
Teraz jest wiele plusów i minusów, które mogę wymyślić, ale tak naprawdę nie mogę zdecydować, które są najważniejsze. Uwaga: jest to aplikacja dla użytkowników końcowych, a nie biblioteka oprogramowania, którą sprzedajemy.
Jakakolwiek rada?
Niektórzy pro dla pierwszego podejścia mogą być:
- KISS - wszystko jest bardzo konkretne. API, ale także implementacja.
- mocno wpisane wartości zwracane.
- dziedziczenie z tej klasy jest głupie. Nic nie można zastąpić, tylko dodać.
- Interfejs API jest bardzo zamknięty, nic nie wchodzi, nic nie można zastąpić, więc mniej może się nie udać.
Niektóre wady:
- Liczba pobierających będzie rosła, ponieważ każde nowe obliczenie, które wymyślimy, jest dodawane do listy
- API jest bardziej prawdopodobne, że zmieni się, a jeśli wprowadzane są przełomowe zmiany, potrzebujemy nowej wersji API, Foot2.
- w przypadku ponownego wykorzystania klasy w innych projektach możemy nie potrzebować wszystkich obliczeń
Niektórzy pro dla drugiego podejścia:
- bardziej elastyczne
- API jest mniej prawdopodobne, że zmieni się (zakładając, że otrzymaliśmy poprawną abstrakcję, jeśli nie, zmiana będzie kosztować więcej)
Niektóre wady:
- luźno wpisane. Potrzebuje rzutów na każde połączenie.
- parametr string - mam złe przeczucia (rozgałęzienie na wartościach string ...)
- Nie ma obecnie przypadku użycia / wymogu, który wymagałby dodatkowej elastyczności, ale może być w przyszłości.
- API nakłada ograniczenia: każde obliczenie musi pochodzić z klasy podstawowej. Uzyskanie obliczeń będzie wymuszone tą metodą 1, a przekazanie dodatkowych parametrów będzie niemożliwe, chyba że opracujemy jeszcze bardziej dynamiczny, superelastyczny sposób przekazywania parametrów, który jeszcze bardziej zwiększy złożoność.
enum
i włączyć jego wartości. Myślę jednak, że druga opcja jest zła, ponieważ odbiega od KISS.getCalculation()
.Odpowiedzi:
Myślę, że w pierwszym podejściu się opłaci. Magiczne ciągi znaków mogą powodować następujące problemy: błędy pisowni, niewłaściwe użycie, nietrywialne bezpieczeństwo typu zwrotu, brak uzupełnienia kodu, niejasny kod (czy ta wersja ma tę funkcję? Myślę, że dowiemy się w czasie wykonywania). Używanie wyliczeń rozwiąże niektóre z tych problemów, ale spójrzmy na podniesione wady:
To prawda, że może to być denerwujące, ale pozwala zachować porządek i ścisłość oraz umożliwia uzupełnianie kodu w dowolnym miejscu projektu w dowolnym nowoczesnym środowisku IDE, z dobrymi komentarzami nagłówkowymi, które są znacznie bardziej przydatne niż wyliczenia.
To prawda, ale to naprawdę ogromny plus;) możesz zdefiniować interfejsy dla częściowych interfejsów API, a następnie nie musisz ponownie kompilować zależnej klasy, na którą nie wpływają nowsze interfejsy API (więc nie potrzebujesz Foot2). To pozwala na lepsze oddzielenie, zależność jest teraz od interfejsu, a nie implementacji. Co więcej, jeśli istniejący interfejs ulegnie zmianie, wystąpi błąd kompilacji w klasach zależnych, co doskonale zapobiega nieaktualnemu kodowi.
Nie rozumiem, jak użycie magicznych ciągów lub wyliczeń pomoże w tym ... Jeśli dobrze rozumiem, albo umieścisz kod w klasie Foot, albo podzielisz go na kilka mniejszych klas, i to dotyczy obu opcji
źródło
IEnumerable<T>.Count
], Takie podejście może pozwolić kodowi cieszyć się korzyściami płynącymi z nowego funkcje interfejsu podczas korzystania z implementacji, które je obsługują, ale zachowują zgodność ze starymi implementacjami.Poleciłbym opcję 3: wyjaśnij, że obliczenia nie są nieodłączną częścią abstrakcji a
Foot
, ale działają na nim. Następnie możesz podzielićFoot
i obliczenia na osobne klasy, takie jak to:W ten sposób nadal masz silne wpisywanie swoich obliczeń i możesz dodawać nowe bez wpływu na istniejący kod (chyba że popełniłeś poważny błąd w informacjach o kwocie ujawnionych przez
Foot
).źródło