Mam problem koncepcyjny z poprawną implementacją kodu, który wydaje się wymagać wielokrotnego dziedziczenia, co nie byłoby problemem w wielu językach OO, ale ponieważ projekt dotyczy Androida, nie ma czegoś takiego jak wielokrotność extends
.
Mam kilka działań, pochodzący z różnych klas bazowych, takich jak proste Activity
, TabActivity
, ListActivity
, ExpandableListActivity
, itd. Również mam pewne fragmenty kodu które należy umieścić w onStart
, onStop
, onSaveInstanceState
, onRestoreInstanceState
i innych standardowych procedur obsługi zdarzeń we wszystkich działaniach.
Jeśli mam jedną klasę bazową dla wszystkich działań, umieściłem kod w specjalnej klasie pochodnej pośredniej, a następnie utworzę wszystkie działania rozszerzające go. Niestety tak nie jest, ponieważ istnieje wiele klas podstawowych. Ale umieszczenie tych samych części kodu w kilku klasach pośrednich nie jest dobrym rozwiązaniem, imho.
Innym podejściem może być utworzenie obiektu pomocnika i przekazanie pomocnikowi wszystkich wywołań wyżej wymienionych zdarzeń. Wymaga to jednak uwzględnienia obiektu pomocnika i ponownego zdefiniowania wszystkich procedur obsługi we wszystkich klasach pośrednich. Tak więc nie ma większej różnicy w stosunku do pierwszego podejścia tutaj - wciąż dużo duplikatów kodu.
Gdyby podobna sytuacja miała miejsce w systemie Windows, podklasę klasę podstawową (coś, co „odpowiada” Activity
klasie w systemie Android) i wychwytywanie tam odpowiednich komunikatów (w jednym miejscu).
Co można w tym celu zrobić w Javie / Androidzie? Wiem, że istnieją ciekawe narzędzia, takie jak instrumentacja Java ( z kilkoma prawdziwymi przykładami ), ale nie jestem guru Java i nie jestem pewien, czy warto spróbować w tym konkretnym przypadku.
Jeśli przegapiłem jakieś inne przyzwoite rozwiązania, proszę je wymienić.
AKTUALIZACJA:
Dla tych, którzy mogą być zainteresowani rozwiązaniem tego samego problemu w Androidzie, znalazłem proste obejście. Istnieje klasa aplikacji , która zapewnia między innymi interfejs ActivityLifecycleCallbacks . Robi dokładnie to, czego potrzebuję, pozwalając nam przechwytywać i dodawać wartości do ważnych wydarzeń dla wszystkich działań. Jedyną wadą tej metody jest to, że jest ona dostępna od poziomu API 14, co w wielu przypadkach nie wystarcza (obsługa interfejsu API na poziomie 10 jest dziś typowym wymogiem).
decordator pattern
. Jest to ostatnia deska ratunku, która faktycznie pokazuje, czego wolałbym unikać - powielania kodu. Przyjmę twoją odpowiedź, jeśli nie pojawią się inne inspirujące pomysły. Czy mogę użyć generycznych do uogólnienia kodu „półproduktów”?Myślę, że próbujesz uniknąć niewłaściwego typu duplikacji kodu. Wierzę, że Michael Feathers napisał o tym artykuł, ale niestety nie mogę go znaleźć. Opisuje to w następujący sposób: możesz myśleć o kodzie, który składa się z dwóch części podobnych do pomarańczy: skórki i miazgi. Skórka to rzeczy takie jak deklaracje metod, deklaracje pól, deklaracje klas itp. Miąższ jest materiałem wewnątrz tych metod; implementacja.
Jeśli chodzi o DRY, chcesz uniknąć powielania miazgi . Ale często w procesie tworzysz więcej skórki. I to jest w porządku.
Oto przykład:
Można to zmienić na następujące:
Dodaliśmy dużo skórki w tym refaktoryzacji. Ale drugi przykład ma znacznie czystsze
method()
i mniej naruszeń DRY.Powiedziałeś, że chcesz uniknąć wzorca dekoratora, ponieważ prowadzi to do powielania kodu. Jeśli spojrzysz na obraz w tym linku, zobaczysz, że będzie on tylko duplikował
operation()
podpis (tj. Skórkę).operation()
Realizacja (masa) powinien być różny dla każdej klasy. Myślę, że w rezultacie twój kod będzie czystszy i będzie mniej duplikacji pulpy.źródło
Wolisz kompozycję niż dziedziczenie. Dobrym przykładem jest „ wzorzec ” IExtension w frameworku .NET WCF. Baiscally masz 3 interfejsy, IExtension, IExtensibleObject i IExtensionCollection. Następnie można komponować różne zachowania za pomocą obiektu IExtensibleObject, dodając instancje IExtension do jego właściwości Extension IExtensionCollection. W Javie powinno to wyglądać mniej więcej tak, ale nie trzeba tworzyć własnej implementacji IExtensioncollection, która wywołuje metody dołączania i odłączania podczas dodawania / usuwania elementów. Należy również pamiętać, że to do Ciebie należy zdefiniowanie punktów rozszerzenia w swojej rozszerzalnej klasie. W przykładzie zastosowano mechanizm wywołania zwrotnego podobny do zdarzenia:
Zaletą tego podejścia jest ponowne użycie rozszerzenia, jeśli uda się wyodrębnić wspólne punkty rozszerzenia między klasami.
źródło
processor.addHandler(console)
warunkiem, że pod warunkiem, żeConsoleProcessor
sam implementuje interfejs zwrotny. Wzorzec „rozszerzenia” wygląda jak połączenievisitor
idecorator
, ale czy w tym przypadku jest to konieczne?Począwszy od Androida 3.0, może być możliwe eleganckie rozwiązanie tego problemu za pomocą Fragmentu . Fragmenty mają własne wywołania zwrotne cyklu życia i mogą być umieszczone w działaniu. Nie jestem jednak pewien, czy to zadziała w przypadku wszystkich wydarzeń.
Inną opcją, której również nie jestem pewien (brakuje dogłębnej wiedzy na temat Androida), może być użycie Dekoratora w odwrotny sposób niż sugeruje to k3b: utwórz
ActivityWrapper
metody wywołania zwrotnego zawierające wspólny kod, a następnie przekaż do owiniętegoActivity
obiektu ( rzeczywiste klasy implementacyjne), a następnie Android powinien uruchomić to opakowanie.źródło
To prawda, że Java nie zezwala na wielokrotne dziedziczenie, ale można by go mniej więcej symulować, czyniąc każdą z podklas SomeActivity rozszerzeniem oryginalnej klasy Activity.
Będziesz miał coś takiego:
źródło