У меня есть несколько классов Java, которые реализуют стратегическую модель. Каждый класс имеет переменные параметры числа различных типов:
interface Strategy {
public data execute(data);
}
class StrategyA implements Strategy {
public data execute(data);
}
class StrategyB implements Strategy {
public StrategyB(int paramA, int paramB);
public data execute(data);
}
class StrategyC implements Strategy {
public StrategyC(int paramA, String paramB, double paramC);
public data execute(data);
}
Теперь я хочу это, пользователь может ввести параметры в некоторый UI. UI должен быть выбран во времени выполнения, т.е. стратегии должны быть независимы от него. Диалоговое окно параметра не должно быть монолитным и должна быть возможность заставить его вести себя и выглядеть по-другому для каждой стратегии и UI (например, консоль или Swing).
Как Вы решили бы эту проблему?
Решение этой проблемы в основном зависит от того, что определяет текущую стратегию. Для простоты я предполагаю, что пользовательский интерфейс одинаков для всех стратегий.
Практически вы создадите класс построителя или фабричный метод. Что-то вроде этого:
interface StrategyPicker {
public Strategy getStrategy();
}
// Most likely used in the JFrame it is added to
class StrategyPickerUI extends JPanel implements StrategyPicker {
// initialize the panel with all the widgets
// and implement the getStrategy method. the getStrategy
// method should be called after the input is done in this
// panel (such as clicking an Ok or Apply button)
}
// You can also make one for the console app
class StrategyPickerSimple implements StrategyPicker {
// ...
}
Если вы хотите по-настоящему фантазировать, вы создаете простой фабричный класс, чтобы исключить процесс создания в его собственный класс:
public class StrategyFactory() {
public static Strategy createStrategyFromParameters(StrategyParams sp) {
// creates the Strategy object... doesn't need to be public static
// and if it isn't, it will help making unit tests easier
}
// This nested class could be split up to StrategyAParams,
// StrategyBParams, StrategyCParams
public class StrategyParams {
data paramA;
int paramB_A;
int paramB_B;
int paramC_A;
String paramC_B;
float paramC_C;
}
}
// in StrategyPickerUI class
public getStrategy() {
StrategyParams sp = new StrategyParams();
sp.paramB_A = myJTextFieldParamB_A.getText();
// and so on...
return StrategyFactory.createStrategyFromParameters(sp);
}
Если вы хотите, чтобы пользовательский интерфейс оставался немонолитным, то разделите ответственность перед собственными объектами. Надеюсь это поможет.
Одна из возможностей сделать это - использовать что-то похожее на шаблон проектирования Строитель:
Для каждого типа стратегии у вас должен быть соответствующий конструктор (один или несколько ). Построитель не работает как обычный построитель, получающий все параметры инициализации в качестве аргументов метода; Вместо этого он должен заблокировать до тех пор, пока не будет получен соответствующий ввод. Некоторые построители будут отображать диалоговое окно Swing и ждать, другие будут печатать на консоли и ждать ввода, третьи могут читать из файла и т. Д. После того, как построитель получит все входные данные, он может создать экземпляр стратегии и вернуть его.
Таким образом, вы отделяете логику извлечения данных от самой стратегии. Еще одним преимуществом является то, что у вас может быть общий интерфейс для всех конструкторов, поэтому, выбрав конкретный конструктор, вы можете управлять им с помощью той же части кода.
Если ваши классы параметров содержат простые объекты (Numbers, Boolean, Date, String), вы можете попробовать сгенерировать свой интерфейс во время выполнения.
Будет сложнее сгенерировать пользовательский интерфейс для составных объектов и коллекции параметров
Посмотрите на Metawidget - это мощный генератор пользовательского интерфейса.