Odziedziczyłem nieco ponad 1000 linii spaghettikod. Mogę rozłożyć to na kilkanaście metod, z których każda tworzy obiekt FinancialTransactionObject, ale przyjmuje różne daty, kwoty i inne parametry, aby utworzyć transakcję.
Moje przeczucie podpowiada mi, żebym uczynił każdą metodę własną klasą. Mogę więc mieć kilkanaście klas dziedziczących z klasy bazowej lub interfejsu z 1 metodą:
abstract FinancialTransactionObject Calculate();
i przenieś parametry do konstruktorów lubuczynić je własnością publiczną. Konstruktorzy oznaczają, że nie mogę ponownie użyć mojej instancji i za każdym razem muszę tworzyć nowy obiekt. Właściwości oznaczają, że konsumujący kod może zapomnieć o ich ustawieniu. Pozostawienie parametrów w każdej metodzie daje mi po prostu kilkanaście metod w oddzielnych plikach i nie jest zorientowane obiektowo.
Wydaje się, że często pojawia się odmiana tego problemu. Czy istnieje dobry, spójny, ogólnobranżowy wzorzec projektowy, aby sobie z tym poradzić?
Odpowiedzi:
0 dla odpowiedzi № 1To naprawdę brzmi dla mnie jak Wzór gościa.
Tak więc podstawową ideą wzorca odwiedzających jest dynamiczna zmiana zachowania w zależności od typu implementacji.
Będziesz potrzebował 2 głównych rzeczy:
IVisitable
zAccept
metoda z rozszerzeniemIVisitor
jako parametr.IVisitor
z wielomaVisit
metody dla każdego wdrożenia zIVisitable
Zacznę od numeru 2.To (w twoim przypadku) będzie interfejs, który zawiera wszystkie implementacje twojej metody obliczeniowej (dla każdej z klas, o których wspomniałeś, które chcesz utworzyć). Zadzwońmy do ciebie Visitor
i Visit
metody Calculator
i Calculate
. Wtedy będziesz miał:
interface ICalculator
{
FinancialTransactionObject Calculate(Element1 element);
FinancialTransactionObject Calculate(Element2 element);
FinancialTransactionObject Calculate(Element3 element);
.
.
}
Wtedy pierwsza część - wszystkie klasy elementów odziedziczą klasę bazową Element
, które zostaną wdrożone IVisitable
. A potem coś takiego:
abstract class Element
{
public FinancialTransactionObject result { get; private set; }
protected void Accept(ICalculator calculator)
{
this.result = calculator.Calculate(this);
}
}
W efekcie otrzymasz coś takiego:
var calculator = new Calculator(); //this is the class that implements the interface
var el1 = new Element1();
var el2 = new Element2();
el1.Accept(calculator);
el2.Accept(calculator);
Wtedy oczywiście na podstawie implementacji Twoje obiekty el będą miały swoje wartości wynikowe.
Nie jestem pewien, czy jest to najlepsze rozwiązanie twojego problemu (jeśli w ogóle takie istnieje), ale wydaje mi się, że jest to to, którego szukasz. Mam nadzieję, że to pomoże.
PS: Myślałem o nazewnictwie IVisitable
do ICalculatable
ale to zabrzmiało dziwnie :)