Niedawno wpadłem na następującą sytuację.
class A{
public:
void calculate(T inputs);
}
Po pierwsze, A
reprezentuje obiekt w świecie fizycznym, co jest silnym argumentem za nierozdzielaniem klasy. Teraz calculate()
okazuje się dość długą i skomplikowaną funkcją. Widzę trzy możliwe struktury:
- napisz to jako ścianę tekstu - zalety - wszystkie informacje są w jednym miejscu
- pisz
private
funkcje użytkowe w klasie i używaj ich wcalculate
ciele - wady - reszta klasy nie zna / nie dba / nie rozumie tych metod napisz
calculate
w następujący sposób:void A::calculate(T inputs){ auto lambda1 = () [] {}; auto lambda2 = () [] {}; auto lambda3 = () [] {}; lambda1(inputs.first_logical_chunk); lambda2(inputs.second_logical_chunk); lambda3(inputs.third_logical_chunk); }
Czy można to uznać za dobrą lub złą praktykę? Czy takie podejście ujawnia jakieś problemy? Podsumowując, czy powinienem uznać to za dobre podejście, gdy znów mam do czynienia z tą samą sytuacją?
EDYTOWAĆ:
class A{
...
public:
// Reconfiguration of the algorithm.
void set_colour(double colour);
void set_density(double density);
void set_predelay(unsigned long microseconds);
void set_reverb_time(double reverb_time, double room_size);
void set_drywet(double left, double right);
void set_room_size(double value);;
private:
// Sub-model objects.
...
}
Wszystkie te metody:
- uzyskać wartość
- oblicz inne wartości bez użycia stanu
- wywołać niektóre z „obiektów podmodelu”, aby zmienić ich stan.
Okazuje się, że poza set_room_size()
tymi metodami po prostu przekazują żądaną wartość do podobiektów. set_room_size()
z drugiej strony wykonuje kilka ekranów niejasnych wzorów, a następnie (2) wykonuje pół ekranu wywoływania seterów podobiektów w celu zastosowania różnych uzyskanych wyników. Dlatego podzieliłem funkcję na dwie lambdy i wywołałem je na końcu funkcji. Gdybym był w stanie podzielić to na bardziej logiczne części, izolowałbym więcej lambdów.
Niezależnie od tego, celem obecnego pytania jest ustalenie, czy taki sposób myślenia powinien się utrzymywać, czy w najlepszym razie nie stanowi wartości dodanej (czytelność, łatwość konserwacji, zdolność debugowania itp.).
Firstly, A represents an object in the physical world, which is a strong argument for not splitting the class up.
Z pewnościąA
reprezentują dane o obiekcie, który mógłby istnieć w świecie fizycznym. Możesz mieć instancjęA
bez rzeczywistego obiektu i prawdziwy obiekt bez instancjiA
, więc traktowanie ich tak, jakby były jednym i tym samym, jest nonsensowne.calculate()
będzie wiedział o tych podfunkcjach.A
, to prowadzi to do skrajności.A
reprezentuje obiekt w świecie fizycznym, co jest mocnym argumentem za tym, aby nie dzielić klasy”. Niestety powiedziano mi to, kiedy zaczynałem programować. Lata zajęło mi uświadomienie sobie, że jest to hokej na trawie. To okropny powód do grupowania rzeczy. Nie potrafię wyartykułować, jakie są dobre powody, by grupować rzeczy (przynajmniej dla mojej satysfakcji), ale ten właśnie należy odrzucić teraz. Koniec końców „dobry kod” polega na tym, że działa poprawnie, jest względnie łatwy do zrozumienia i stosunkowo łatwy do zmiany (tj. Zmiany nie mają dziwnych skutków ubocznych).Odpowiedzi:
Nie, ogólnie nie jest to dobry wzór
To, co robisz, polega na rozbiciu funkcji na mniejsze funkcje za pomocą lambda. Istnieje jednak znacznie lepsze narzędzie do dzielenia funkcji: funkcji.
Lambdy działają, jak widzieliście, ale znaczą o wiele, wiele więcej, niż zwykłe rozbicie funkcji na lokalne elementy. Lambdas:
Gdy tylko włączysz lambdy do miksu, następny programista, który zajrzy do kodu, musi natychmiast załadować mentalnie wszystkie te reguły, przygotowując się do zobaczenia, jak działa Twój kod. Nie wiedzą, że nie będziesz korzystać z całej tej funkcjonalności. Jest to bardzo kosztowne w porównaniu do alternatyw.
To tak, jakbyś używał motyki do ogrodnictwa. Wiesz, że używasz go tylko do kopania małych dziur na tegoroczne kwiaty, ale sąsiedzi się denerwują.
Pomyśl, że wszystko, co robisz, to grupowanie kodu źródłowego wizualnie. Kompilator tak naprawdę nie dba o to, abyś curry rzeczy z lambdas. W rzeczywistości spodziewałbym się, że optymalizator natychmiast cofnie wszystko, co właśnie zrobiłeś podczas kompilacji. Obsługujesz wyłącznie kolejnego czytelnika (Dziękujemy za zrobienie tego, nawet jeśli nie zgadzamy się co do metodologii! Kod jest czytany znacznie częściej niż jest napisany!). Wszystko, co robisz, to funkcja grupowania.
// ------------------
między każdą częścią.EDYCJA: Patrząc na twoją edycję z przykładowym kodem, pochylam się, aby notacja komentarza była najczystsza, z nawiasami, aby wymusić granice sugerowane przez komentarze. Jednak jeśli którakolwiek z funkcji może być ponownie użyta w innych funkcjach, zalecam użycie funkcji zamiast tego
źródło
count++
)calculate()
na{}
bloki i deklarując udostępnione dane wcalculate()
zakresie. Myślałem, że widząc, że lambdas nie schwytają, czytelnik nie będzie obciążony mocą lambdas.lambda
jest niesprawiedliwa, czy też niegrzecznie zmuszasz ludzi do przestrzegania ścisłej denotacji, nie jest łatwym pytaniem. W rzeczywistości może być całkowicie akceptowalne, abyś używałlambda
tego w swojej firmie i zupełnie nie do zaakceptowania w mojej firmie, i żadne z nich nie musi się mylić!lambda
, takie jakfor_each
funkcja. W związku z tym, gdy widzę,lambda
że nie pasuje do jednego z tych łatwych do wykrycia problemów, pierwsze założenie, że doszedłem do wniosku, to, że prawdopodobnie będzie on używany do programowania funkcjonalnego, ponieważ inaczej nie był potrzebny. Dla wielu programistów programowanie funkcjonalne jest zupełnie innym sposobem myślenia niż programowanie proceduralne lub programowanie OO.Myślę, że źle przyjęłeś:
Nie zgadzam się z tym. Na przykład, gdybym miał klasę reprezentującą samochód, zdecydowanie chciałbym go podzielić, ponieważ z pewnością chcę, aby mniejsza klasa reprezentowała opony.
Tę funkcję należy podzielić na mniejsze funkcje prywatne. Jeśli naprawdę wydaje się oddzielony od innej części klasy, może to oznaczać, że klasa powinna być oddzielona. Oczywiście trudno powiedzieć bez wyraźnego przykładu.
W tym przypadku nie widzę korzyści z używania funkcji lambda, ponieważ tak naprawdę nie czyści kodu. Zostały one stworzone, aby wspomóc programowanie w stylu funkcjonalnym, ale to nie wszystko.
To, co napisałeś, przypomina trochę zagnieżdżone obiekty funkcyjne w stylu Javascript. Co znowu jest znakiem, że należą do siebie ściśle. Czy jesteś pewien, że nie powinieneś tworzyć dla nich osobnej klasy?
Podsumowując, nie sądzę, że jest to dobry wzór.
AKTUALIZACJA
Jeśli nie widzisz żadnego sposobu na zawarcie tej funkcjonalności w znaczącej klasie, możesz utworzyć funkcje pomocnicze o zasięgu pliku, które nie są członkami twojej klasy. To w końcu C ++, projektowanie OO nie jest koniecznością.
źródło
A
(może nawet funktor z wszystkimi innymi metodami prywatnymi)? Klasa zadeklarowana i zdefiniowana w środkucalculate()
(wygląda to bardzo podobnie do mojego przykładu lambda). Jako wyjaśnienie,calculate()
jest jedną z rodziny metod (calculate_1(), calculate_2()
itp.), Z których wszystkie są proste, tylko ta jest 2 ekranami formuł.calculate()
o wiele dłuższy niż wszystkie inne metody?