Вот в таком классе мне недавно пришлось исправлять ошибку:
public abstract class UpdaterBase {
protected abstract IMyControl CreateMyControl();
protected abstract IMySettingsStore CreateMySettingsStore(IMyControl control);
public void Update(MyTarget target) {
if(target != null && !MySettingsHelper.HasSettings(target)) {
IMyControl control = CreateMyControl();
control.Fields["Priority"].Area = MyArea.ColumnArea;
control.Fields["Subject"].Area = MyArea.DataArea;
control.Fields["AssignedTo.DisplayName"].Area = MyArea.RowArea;
MySettingsHelper.SaveSettings(CreateMySettingsStore(control), target);
}
}
}
protected abstract IMyControl CreateMyControl();
protected abstract IMySettingsStore CreateMySettingsStore(IMyControl control);
public void Update(MyTarget target) {
if(target != null && !MySettingsHelper.HasSettings(target)) {
IMyControl control = CreateMyControl();
control.Fields["Priority"].Area = MyArea.ColumnArea;
control.Fields["Subject"].Area = MyArea.DataArea;
control.Fields["AssignedTo.DisplayName"].Area = MyArea.RowArea;
MySettingsHelper.SaveSettings(CreateMySettingsStore(control), target);
}
}
}
На первый взгляд этот код выглядит нормально: базовая логика для использования и перекрывания и все такое про ООП и полиморфизм. И даже наследники есть:
public class MyUpdaterWin : UpdaterBase {
protected override IMyControl CreateMyControl() {
return new MyControlWin();
}
protected override IMySettingsStore CreateMySettingsStore(IMyControl control) {
return new MySettingsStoreWin(((MyControlWin)control).WinGrid);
}
}
public class MyUpdaterWeb : UpdaterBase {
protected override IMyControl CreateMyControl() {
return new MyControlWeb();
}
protected override IMySettingsStore CreateMySettingsStore(IMyControl control) {
return new MySettingsStoreWeb(((MyControlWeb)control).WebGrid);
}
}
Тоже вроде нормально выглядит в лучших традициях полиморфизма, хотя вот эти преобразования "((MyControlWeb)control).WebGrid" выглядят не очень хорошо. И я решил посмотреть на реальное использование этих классов:
new MyUpdaterWin().Update(myTarget);
и
new MyUpdaterWeb().Update(myTarget);
Это уже совсем не похоже на необходимость применения полиморфизма.
Такая логика гораздо легче кодируется на прямом алгоритме без ветвлений в виртуальных и перекрытых методах:
if(myTarget != null && !MySettingsHelper.HasSettings(myTarget )) {
MyControlWin control = new MyControlWin();
control.Fields["Priority"].Area = MyArea.ColumnArea;
control.Fields["Subject"].Area = MyArea.DataArea;
control.Fields["AssignedTo.DisplayName"].Area = MyArea.RowArea;
MySettingsHelper.SaveSettings(new MySettingsStoreWin(control.WinGrid), target);
}
MyControlWin control = new MyControlWin();
control.Fields["Priority"].Area = MyArea.ColumnArea;
control.Fields["Subject"].Area = MyArea.DataArea;
control.Fields["AssignedTo.DisplayName"].Area = MyArea.RowArea;
MySettingsHelper.SaveSettings(new MySettingsStoreWin(control.WinGrid), target);
}
В таком варианте кода гораздо проще понять "а что же тут собственно делается-то?" без прыжков "базовый класс->наследник->базовый класс->другой наследник->опять базовый класс->а что я вообще начал смотреть?"
Так как вызовов у меня было два:
new MyUpdaterWeb().Update(myTarget);
new MyUpdaterWin().Update(myTarget);
new MyUpdaterWin().Update(myTarget);
то под них я сделал метод:
public static class UpdaterBase {
public static void Update(MyTarget target, IMyControl control, ISettingsStore settingsStore) {
control.Fields["Priority"].Area = MyArea.ColumnArea;control.Fields["Subject"].Area = MyArea.DataArea;
control.Fields["AssignedTo.DisplayName"].Area = MyArea.RowArea;
MySettingsHelper.SaveSettings(settingsStore, target);
}
и вызвал его с двумя наборами параметров:
MyControlWin control = new MyControlWin();
UpdaterBase.Update(myTarget, control, new MySettingsStore(control.WinGrid));
и
MyControlWeb control = new MyControlWeb();
UpdaterBase.Update(myTarget, control, new MySettingsStore(control.WebGrid));
Такое применение наследования и полиморфизма заметно затрудняет понимание логики работы и увеличивает стоимость сопровождения кода. Такой выбор оформления кода должен быть обусловлен реальным использованием и невозможностью применения более простых приемов. В моем примере реального применения не было, а логика отлично влезла в статические методы с параметрами. Такое оформление позволяют очень легко разобраться с возникающими ошибками за счет линейного построения кода в единственной функции.
Комментариев нет:
Отправить комментарий