斯卡拉工厂模式
在尝试写更多的可测试的Java代码,我一直使用Martin Fowler的博客上讲述年前的模型 - 视图 - 演示模式(http://martinfowler.com/eaaDev/ModelViewPresenter.html - 是啊,我知道他不赞成它,但我还是喜欢简单)。斯卡拉工厂模式
我为每一个的JFrame,JDialog的等视图界面,并使用一个工厂实际生成它们,这样我可以生成单元测试的嘲笑。
下面是一个小组样本的类和接口的。斯卡拉比直接的语法翻译有更好的方法吗?换句话说,我如何使用特质,自我类型引用等来更好地遵循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);
}
}
UPDATE::我意识到,我一个similar question去年提出,并得到了不同的“最佳”答案。看看sblundy的答案 - 非常好。
我会看看的cake-pattern。它通常用于执行完全依赖注入,而不是仅仅抽象出对象构造,但它也可以提供。其基本思想是你捆绑你的应用程序配置为特点,你再混合在一起,产生的运行和测试设置:
trait GUI {
trait View { /* ... */ }
def buildView(): View
}
/**
* Your "real" application
*/
object RealGUI extends GUI {
def buildView() = newView(/*...*/)
}
/**
* Your mocked-up test application
*/
object TestGUI extends GUI {
def buildView() = createMock(classOf[View])
}
setInstance
使
DialogFactory.getInstance
使用模拟
DialogFactory
事实
除了,您可以让object Dialog
成为创建Dialog
的工厂。类型(清单)=>选项[类型]函数:
是的,但我不能想出任何其他方式来模拟对话框。 – Ralph 2011-03-11 18:01:59
电梯由具有一般工厂接口,其中有一个提供做的。它的定义是这样的(我认为):
trait Factory {
def provide[T: Manifest]: Option[T]
}
所有这些你正在做的反射东西是相当矫枉过正的(即使在Java中)。你应该在'DialogFactory'中重写'newView'并直接调用'Dialog'构造函数。与编写'DialogFactory'构造函数的代码量相同,'newView'会抛出更少的异常。 – 2011-03-11 16:52:46
@Ken Bloom:我仍然试图改进Java版本。感谢您的建议。我会看看它。 – Ralph 2011-03-11 18:01:18