Problem
Pracuję nad projektem w języku Python, którego główną klasą jest nieco „ Boski obiekt ”. Jest tak cholernie wiele atrybutów i metod!
Chcę refaktoryzować klasę.
Jak dotąd…
W pierwszym kroku chcę zrobić coś stosunkowo prostego; ale kiedy wypróbowałem najprostsze podejście, przełamało kilka testów i istniejących przykładów.
Zasadniczo klasa ma długą listę atrybutów - ale mogę je przejrzeć i pomyśleć: „Te 5 atrybutów jest powiązanych… Te 8 są również powiązane… a potem jest cała reszta”.
getattr
Zasadniczo chciałem po prostu zgrupować powiązane atrybuty w klasę pomocnika przypominającą dykt. Miałem wrażenie, __getattr__
że byłby idealny do tej pracy. Przeniosłem więc atrybuty do osobnej klasy i, oczywiście, __getattr__
działałem doskonale magicznie…
Na pierwszy .
Ale potem spróbowałem uruchomić jeden z przykładów. Przykładowa podklasa próbuje ustawić jeden z tych atrybutów bezpośrednio (na poziomie klasy ). Ale ponieważ atrybut nie był już „fizycznie umiejscowiony” w klasie nadrzędnej, wystąpił błąd informujący, że atrybut nie istnieje.
@własność
Potem przeczytałem o @property
dekoratorze. Ale potem przeczytałem również, że stwarza to problemy dla podklas, które chcą zrobić, self.x = blah
gdy x
są własnością klasy nadrzędnej.
Pożądany
- Niech cały kod klienta nadal działa
self.whatever
, nawet jeśli kod nadrzędnywhatever
nie jest „fizycznie zlokalizowana” w samej klasie (lub instancji). - Grupuj powiązane atrybuty w pojemniki podobne do dict.
- Zmniejsz ekstremalną głośność kodu w klasie głównej.
Na przykład nie chcę po prostu tego zmieniać:
larry = 2
curly = 'abcd'
moe = self.doh()
Zaangażowany w to:
larry = something_else('larry')
curly = something_else('curly')
moe = yet_another_thing.moe()
… Ponieważ wciąż jest głośno. Chociaż z powodzeniem przekształca to po prostu atrybut w coś, co może zarządzać danymi, oryginał miał 3 zmienne, a poprawiona wersja wciąż ma 3 zmienne.
Byłbym jednak w porządku z czymś takim:
stooges = Stooges()
A jeśli wyszukiwanie self.larry
nie powiedzie się, coś sprawdzi stooges
i zobaczy, czy larry
jest. (Ale musi także działać, jeśli podklasa próbuje to zrobić larry = 'blah'
na poziomie klasy).
Podsumowanie
- Chcesz zastąpić pokrewne grupy atrybutów w klasie nadrzędnej jednym atrybutem, który przechowuje wszystkie dane w innym miejscu
- Chcesz pracować z istniejącym kodem klienta, który używa (np.)
larry = 'blah'
Na poziomie klasy - Chcesz nadal zezwalać na rozszerzanie, zastępowanie i modyfikowanie tych podklas atrybutów podklas bez wiedzy, że coś się zmieniło
czy to możliwe? A może szczekam niewłaściwe drzewo?