tło
Pracuję nad trwającym projektem C #. Nie jestem programistą C #, przede wszystkim programistą C ++. Więc przydzielono mi w zasadzie łatwe i refaktoryzujące zadania.
Kod to bałagan. To ogromny projekt. Ponieważ nasz klient domagał się częstych wydań z nowymi funkcjami i poprawkami błędów, wszyscy inni programiści byli zmuszeni stosować brutalną siłę podczas kodowania. Kod jest wysoce niemożliwy do utrzymania i wszyscy inni programiści się z nim zgadzają.
Nie jestem tutaj, by debatować, czy zrobili to dobrze. Podczas refaktoryzacji zastanawiam się, czy robię to we właściwy sposób, ponieważ mój refaktoryzowany kod wydaje się skomplikowany! Oto moje zadanie jako prosty przykład.
Problem
Istnieje sześć klas: A
, B
, C
, D
, E
i F
. Wszystkie klasy mają funkcję ExecJob()
. Wszystkie sześć implementacji jest bardzo podobnych. Zasadniczo na początku A::ExecJob()
zostało napisane. Następnie wymagana była nieco inna wersja, która została zaimplementowana B::ExecJob()
przez modyfikację kopiuj-wklej- A::ExecJob()
. Kiedy wymagana C::ExecJob()
była inna, nieco inna wersja, została napisana i tak dalej. Wszystkie sześć implementacji ma jakiś wspólny kod, następnie kilka różnych wierszy kodu, a następnie znowu wspólny kod i tak dalej. Oto prosty przykład realizacji:
A::ExecJob()
{
S1;
S2;
S3;
S4;
S5;
}
B::ExecJob()
{
S1;
S3;
S4;
S5;
}
C::ExecJob()
{
S1;
S3;
S4;
}
Gdzie SN
jest grupa dokładnie takich samych stwierdzeń.
Aby były wspólne, stworzyłem inną klasę i przeniosłem wspólny kod w funkcji. Użycie parametru do kontroli, która grupa instrukcji powinna zostać wykonana:
Base::CommonTask(param)
{
S1;
if (param.s2) S2;
S3;
S4;
if (param.s5) S5;
}
A::ExecJob() // A inherits Base
{
param.s2 = true;
param.s5 = true;
CommonTask(param);
}
B::ExecJob() // B inherits Base
{
param.s2 = false;
param.s5 = true;
CommonTask(param);
}
C::ExecJob() // C inherits Base
{
param.s2 = false;
param.s5 = false;
CommonTask(param);
}
Zauważ, że w tym przykładzie zastosowano tylko trzy klasy i uproszczone instrukcje. W praktyce CommonTask()
funkcja wygląda na bardzo złożoną przy wszystkich tych kontrolach parametrów i jest o wiele więcej instrukcji. Ponadto w prawdziwym kodzie znajduje się kilka CommonTask()
funkcji podglądających.
Chociaż wszystkie implementacje współużytkują wspólny kod, a ExecJob()
funkcje wyglądają ładniej, istnieją dwa problemy, które mnie niepokoją:
- W przypadku każdej zmiany
CommonTask()
należy przetestować wszystkie sześć (i być może w przyszłości) funkcji. CommonTask()
jest już złożony. Z czasem stanie się bardziej złożony.
Czy robię to we właściwy sposób?