草庐IT

java泛型设计问题(状态机)

coder 2023-08-28 原文

我制作了一个状态机,希望它能利用 Java 中的泛型。目前我看不出有什么方法可以使它工作并获得漂亮 的代码。我确信这个设计问题之前已经被解决过很多次,我正在寻找一些输入。这是一个粗略的轮廓。

class State { ... }

每个不同的状态对象只有一个副本(主要是绑定(bind)到静态最终变量的匿名类),它具有每个状态的自定义数据。每个状态对象都有一个状态父级(有一个根状态)

class Message { ... } 

每条消息都是单独创建的,每条消息都有自定义数据。他们可以相互子类化。有一个根消息类。

class Handler { ... } 

每个处理程序只创建一次并处理特定的状态/消息组合。

class StateMachine { ... }

当前跟踪当前状态,以及所有 (State,Message) -> Handler 映射的列表。它还具有其他功能。我试图让这个类保持通用,并使用类型参数对其进行子类化,因为它在我的程序中使用了很多次,并且每次都使用一组不同的 Message/State 的/和 Handler 的。不同的 StateMachine 将为其处理程序提供不同的参数。

方法A

让状态机跟踪所有映射。

class StateMachine<MH extends MessageHandler> {
  static class Delivery {
    final State state;
    final Class<? extends Message> msg;
  }
  HashMap<Delivery, MH> delegateTable;
  ...
}

class ServerStateMachine extends StateMachine<ServerMessageHandler> {
  ...
}

允许我为这个特定的状态机自定义处理程序方法。 handler.process 方法的参数可以被覆盖。但是,处理程序不能由消息类型参数化。

问题:这涉及到对每个消息处理程序使用 instanceof 健全性检查(确保它收到它期望的消息)。

方法B

让每个消息处理程序按消息类型参数化

class MessageHandler<M extends Message> {
  void process(M msg) { .... }
}

问题:类型删除将阻止我将它们存储在一个漂亮的 HashMap 中,因为所有 MessageHandler 的类型都不同。如果我可以将它们存储在 map 中,我将无法检索它们并使用适当的参数调用它们。

方法C

让状态对象处理所有消息。

class State<M extends Message> { ... }
class ServerState<M extends ServerMessage> extends State<M> { ... }

我有绑定(bind)到特定状态机状态的消息处理程序(通过将它们放入内部),(状态机的每个实例都有自己的有效状态列表),这允许处理程序属于特定类型。 (服务器状态机 -> 服务器消息处理程序)。

问题:每个状态只能处理一种消息类型。您还会失去父状态可以处理与子状态不同的消息的想法。类型删除还可以防止 StateMachine 调用当前状态处理方法。

方法D

根据状态自行处理消息。

问题:从来没有真正考虑过,因为每条消息都应该有一个基于当前状态机状态的不同处理程序。发送方将不知道当前 StateMachine 的状态。

方法E

用 switch 语句忘记泛型和硬代码状态/消息处理。

问题: 理智

不安全的解决方案:

感谢大家的投入,我认为问题是我没有将其归结为好问题(过多的讨论),这就是我现在所拥有的。

public class State { }

public class Message { }

public class MessageHandler<T extends Message> { }

public class Delivery<T extends Message> {
  final State state;
  final Class<T> msgClass;
}

public class Container {

  HashMap<Delivery<? extends Message>, MessageHandler<? extends Message>> table;

  public <T extends Message> add(State state, Class<T> msgClass, MessageHandler<T> handler) {
    table.put(new Delivery<T>(state, msgClass), handler);
  }

  public <T extends Message> MessageHandler<T> get(State state, T msg) {
    // UNSAFE - i cannot cast this properly, but the hashmap should be good
    MessageHandler<T> handler = (MessageHandler<T>)table.get(new Delivery<T>(state, msg.getClass()));
    return handler;
  }

}

最佳答案

用枚举表示状态和消息的 E 可能是最简单的。但它的可扩展性不是很好。

C 在状态类中使用访问者模式来分派(dispatch)消息类型看起来可能是您的最佳选择。如果在 instanceof 和 Visitor 之间进行选择,我认为 Visitor 稍微干净一些(尽管仍然很尴尬)。类型删除问题确实造成了很大的困难,并且消息中的处理似乎有些倒退。典型的状态机符号将状态作为控制中心。此外,您可以让消息类型的 Visitor 抽象类在所有状态上抛出错误,从而允许状态免费获得无效消息的错误回退。

C+Visitor 与我在用 C 或具有一流函数的语言实现状态机时经常使用的方法非常相似——“状态”由指向当前状态中处理消息的函数的指针表示,其中该函数返回指向下一个状态函数(可能是它自己)的指针。状态机控制循环仅获取下一条消息,将其传递给当前状态函数,并在返回时更新“当前”的概念。

关于java泛型设计问题(状态机),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1301007/

有关java泛型设计问题(状态机)的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  4. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  5. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  6. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  7. ruby - Fast-stemmer 安装问题 - 2

    由于fast-stemmer的问题,我很难安装我想要的任何ruby​​gem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=

  8. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  9. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  10. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

随机推荐