一个应用程序可以以两种模式运行--“实时”模式,它查看世界状态的每一次更新,或者“采样”模式,其中它只查看世界的状态--每T毫秒一次。
如果我正在编写Haskell (或任何使用ADTs的语言),我会将其建模为
data Mode = RealTime | Sampled Int可以按以下方式以类型安全的方式使用
case mode of
RealTime -> -- do realtime stuff
Sampled interval -> -- do sample stuff with 'interval'我说它是“类型安全”,因为如果您在实时模式下运行,您将无法尝试访问interval字段(如果您在采样模式下运行,则在需要时提供该字段)。
我如何以一种类型安全的方式在Java中建模相同的东西?也就是说,我想
interval字段,以及这在Java中是可能的吗?如果不是,实现这种类型安全的惯用方法是什么?
发布于 2015-07-15 11:51:53
在像Java这样的语言中模拟封闭的代数数据类型的传统方法是访客模式,它只提供开放的类(可以在任何时候继承)。
abstract class Mode {
public abstract <T> T accept(ModeVisitor<T> visitor);
}
final class RealTime extends Mode {
public RealTime() {}
public <T> T accept(ModeVisitor<T> visitor) {
return visitor.visit(this);
}
}
final class Sampled extends Mode {
private final int interval;
public Sampled(int interval) {
this.interval = interval;
}
public int getInterval() {
return this.interval;
}
public <T> T accept(ModeVisitor<T> visitor) {
return visitor.visit(this);
}
}
// The recursion principle itself
abstract class ModeVisitor<T> {
public abstract T visit(RealTime mode);
public abstract T visit(Sampled mode);
}
// Concrete uses of the recursion principle
final class ModeShow extends ModeVisitor<String> {
private ModeShow() {}
public static String show(Mode mode) {
return mode.accept(new ModeShow());
}
public String visit(RealTime mode) {
return "RealTime";
}
public String visit(Sampled mode) {
return "Sampled " + mode.getInterval();
}
}正如@ over 3237465所指出的,数据类型的几个编码是可能的,当数据类型不是递归的时候,这些编码恰好是一致的: Church编码是折叠的:它允许您通过教堂编码的数据类型递归积累一个值。Scott编码对应于实际的模式匹配。在任何情况下,访问者都可以用来实现所有这些编码。谢谢你的催促,@ nudge 3237465!
发布于 2015-07-15 11:23:58
您可以声明一个接口Mode
public interface Mode {
void doSmth();
}然后可以有两个类实现该接口。
public class Realtime implements Mode {
@Override
public void doSmth() {
// Do realtime stuff
}
}
public class Sampled implements Mode {
private final int interval;
public Sampled(final int interval) {
this.interval = interval;
}
@Override
public void doSmth() {
// Do sampled stuff
}
}然后声明一个类型为Mode的变量
final Mode mode = ... // Initialize however you want, calling one of the constructors.然后,由于mode是Mode类型的,所以只能访问接口中声明的内容。因此,您只需调用mode.doSmth(),根据初始化mode的方式,它将实时运行或采样。
如果这些类共享一些代码,那么您可以声明一个abstract类而不是一个interface,并且有两个类extend该类。因此,他们可以调用在abstract类中声明的常用方法(应该使用protected可见性来声明这些方法,这样只有子类才能看到它们)。
发布于 2015-07-15 11:39:41
是的,它是有可能的,尽管它取决于你准备达到的复杂程度。
如果您想达到最高级别的类型安全性,我建议您声明一个抽象(名为AbstractModeManager),其职责是查询世界状态并将其存储在实例变量中,这些变量应该可以通过公共getter方法访问。它还必须知道何时有最新情况:
abstract class AbstractModeManager
{
// Instance variables to contain the last state read.
private ... state;
protected void queryTheStateOfTheWorld(...) throws ...
{
... fill this.state ...
}
public ... getState()
{
return this.state;
}
public abstract void updateOccurred(...);
}在这种情况下,您必须编写两个实现:一个用于实时实现,另一个用于采样:
class RealTimeModeManager extends AbstractModeManager
{
public void updateOccurred(...)
{
// In this implementation, every time there has been an update,
// a query must be performed:
queryTheStateOfTheWorld(...);
}
}
class SampledModeManager extends AbstractModeManager
{
public SampledModeManager(int interval)
{
... program a timer to call the queryTheStateOfTheWorld ...
}
public void updateOccurred(...)
{
// Do nothing.
}
}最后,您必须决定在每种情况下必须使用哪一种,并将其存储在一个变量中:
private AbstractModeManager mode=.....。并在系统中的每次更新中系统地调用它:
mode.updateOccurred(...)这样,在初始化该变量之后,您将不会关心系统运行的是哪种模式:这种行为将留给您的抽象处理。
https://stackoverflow.com/questions/31428870
复制相似问题