Пытаясь написать более тестируемый Java-код, я использовал шаблон Model-View-Presenter, который Мартин Фаулер опубликовал в своем блоге несколько лет назад (http://martinfowler.com/eaaDev/ModelViewPresenter.html -- да, я знаю, что он устарел, но мне все равно нравится простота).
Я создаю интерфейс View для каждого JFrame, JDialog и т. д. и использую Factory для фактического их создания, чтобы я мог создавать макеты для модульного тестирования.
Ниже приведен небольшой набор примеров классов и интерфейсов. Есть ли лучший способ в Scala, чем прямой перевод синтаксиса? Другими словами, как мне использовать трейты, ссылки на собственный тип и т. д., чтобы лучше следовать принципам DRY и при этом писать безопасный для типов код?
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionListener;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JButton;
import javax.swing.JDialog;
interface View {
void okButtonAddActionListener(final ActionListener actionListener);
}
class Dialog
extends JDialog
implements View {
private final JButton okButton = new JButton("OK");
public Dialog(final Window owner,
final ModalityType modalityType) {
super(owner, modalityType);
}
public void okButtonAddActionListener(final ActionListener actionListener) {
okButton.addActionListener(actionListener);
}
}
interface ViewFactory<I, C extends I> {
I newView(final Window owner,
final ModalityType modalityType)
throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException;
}
class AbstractViewFactory<I, C extends I>
implements ViewFactory<I, C> {
private final Class<C> cls;
public AbstractViewFactory(Class<C> cls) {
this.cls = cls;
}
public I newView(final Window owner,
final ModalityType modalityType)
throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
final Constructor<C> constructor = cls.getConstructor(Window.class, ModalityType.class);
return constructor.newInstance(owner, modalityType);
}
}
class DialogFactory
extends AbstractViewFactory<View, Dialog> {
private static final class InstanceHolder {
public static ViewFactory<View, Dialog> instance = new DialogFactory();
}
public DialogFactory() {
super(Dialog.class);
}
public static ViewFactory<View, Dialog> getInstance() {
return InstanceHolder.instance;
}
public static void setInstance(final ViewFactory<View, Dialog> instance) {
InstanceHolder.instance = instance;
}
}
// Here is a typical usage in production
class DialogFactoryUser {
private void userFactory() {
final Window window = new Window(null);
try {
final View view = DialogFactory.getInstance().newView(window, ModalityType.APPLICATION_MODAL);
} catch (final Exception ex) {
ex.printStackTrace();
}
}
}
// Here is a typical usage in a unit test
class Test {
public void test() {
...
mockView = createMock(View.class);
final Window window = new Window(null);
mockViewFactory = createMock(ViewFactory.class);
expect(mockViewFactory.newView(window, ModalityType.APPLICATION_MODAL)).andReturn(mockView);
...
DialogFactory.setInstance(mockViewFactory);
}
}
ОБНОВЛЕНИЕ:: я понял, что задал похожий вопрос в прошлом году и получил другой «лучший» ответ. Посмотрите ответ sblundy - очень приятно.
newView
вDialogFactory
и напрямую вызвать конструкторDialog
. Это тот же объем кода, что и написание конструктораDialogFactory
прямо сейчас, аnewView
вызовет меньше исключений. - person Ken Bloom   schedule 11.03.2011