gpt4 book ai didi

java - 如何解决对全局设置/事件注册表的类型安全异议?

转载 作者:行者123 更新时间:2023-12-01 18:39:39 25 4
gpt4 key购买 nike

我正在开发一个客户的 Java 应用程序,其中包含多个项目和插件。它们的设计非常脆弱,因为跨这些部门共享任何信息都涉及一些上帝类实例化和注册实现特定接口(interface)的类。这些接口(interface)不受控制地激增,并且通常包含客户端不需要的约定方法。

为了解耦一切,我提出了几个处理“设置”和“事件”的交换所对象。任何类都可以请求设置,指定枚举中的设置类型和预期值的类型。任何类都可以注册一个设置源,该设置源实现一个定义如何获取该设置的接口(interface)(例如,通过检查某个类中的某些变量来检查网络是否可用),但更常见的是,我可以将某些变量与原始类完全分离,并且它会 float eternity 作为匿名设置源,仅接受并发布一些设置值。

//code from caller requesting the setting value
long netID = Setting.GetLongSetting(Setting.Type.NetworkID);

//one of those self-defined settings
Setting.RegisterLongSource(Setting.Type.NetworkID, new LongSource() {
private long myID=-1;

@Override
public long getValue() {
return myID;
}

@Override
public void setValue(long l) {
myID = l;
}

@Override
public Setting.Type getType() {
return Setting.Type.NetworkID;
}
});

事件的注册方式与从 C# 大量借用的 EventArg 对象类似。

//code from an event generator
Events.Event(Event.Type.MessageReceived, new ObjectEventArg(messageInstance));

//An anonymous event listener that expects a message object and passes it to a method for processing
Events.RegisterListener(Event.Type.MessageReceived, new Event.Listener() {
@Override
public void HandleEvent(Event.Type type, EventArg e) {
if(type!=Event.Type.MessageReceived)
{
try
{
Message m = (Message) ((ObjectEventArgs)e).value;
if(m!=null)
{
this.handleMessage(m);
}
else
{
//error 3
}
}
catch
{
//error 2
}
}
else
{
//error 1
}
}
});

这些设计存在一些问题,我的客户要求我考虑具有更高编译时安全性的东西。例如,事件中有 3 次出现错误的机会。事件监听器应该不可能获取它未注册的事件类型(错误 1),但我至少应该检查一下。无法保证 EventArg 类型是正确的类型,或者传入 ObjectEventArg 的对象将符合预期(错误 2)。无法保证传递的引用不为 null(错误 1)。所有这些都很大程度上取决于代码的良好行为,而在编译时无法保证。就此而言,有人可以尝试创建接受字符串而不是长字符串的时间设置,谁能说哪个是正确的?

我可以做些什么来改进这个设计,避免一些未知因素,并提供编译时保证?

-------------编辑----------------根据 @Jason Albano 的回答,我可以像这样重写我的解决方案。

//Settings now return a defined type; It could still be null or the wrong type was registered
//if I go all the way with his solution I won't need to cast, but I will have one register/get method for each type.
NetworkIDSetting netID = (NetworkIDSetting) Setting.GetSetting(Setting.Type.NetworkID);

//I can still create a self-defined setting
class NetworkIDSetting() {
private long myID=-1;

public long getValue() {
return myID;
}

public void setValue(long l) {
myID = l;
}

@Override
public Setting.Type getType() {
return Setting.Type.NetworkID;
}
}

//i'm less certain how to create a setting that is bound more tightly to another class.
abstract class ScreenWidthSetting {
public abstract int getWidth();

//set width is not allowed in this case

@Override
public Setting.Type getType() {
return Setting.Type.ScreenWidth;
}
}

//then instantiate in the required class
Setting.RegisterLongSource(new ScreenWidthSetting() {
@Override
public int getWidth() {
this.getScreen().getWidth();
}
});

//definition of an event class
class MessageReceivedEvent {
public Message myMessage;
public MessageReceivedEvent(Message m) {
myMessage = m;
}

@Override
public Event.Type getEventType() {
return Event.Type.MessageReceived;
}
}

//code from an event generator
Events.Event(new MessageReceivedEvent(messageInstance));

//I can still create an anonymous event listener with many more guarantees
//again, if I go the whole way I will have a multiplicity of very similar methods
Events.RegisterListener(Event.Type.MessageReceived, new Event.MessageListener() {
@Override
public void HandleEvent(MessageEvent e) {
Message m = e.myMessage;
if(m!=null)
{
this.handleMessage(m);
}
else
{
//error 3 is still unavoidable
}
}
}

最佳答案

维护类型安全正是Visitor Pattern专为。

访问者模式将对象上执行的操作与对象本身分开。在这种情况下,操作是处理程序,对象是事件。该模式的工作原理为 double dispatch ,其中方法调用的行为因调用该方法的对象以及提供给该方法的参数而异。

对于处理程序和事件,我们可以创建以下内容:

public interface Handler {
void handle(EventA a);
void handle(EventB b);
}

public interface Event {
void accept(Handler handler);
}

public class EventA implements Event {

@Override
public void accept(Handler handler) {
handler.handle(this);
}
}

public class EventB implements Event {

@Override
public void accept(Handler handler) {
handler.handle(this);
}
}

在每个具有相同 handler.handle(this) 主体的每个 Event 具体类中继续实现 accept 方法可能看起来很乏味,但这是模式的关键。 this 引用维护进行调用的类的类型。因此,对于 EventA 类,当 accept 被调用时,对 handler.handle(this) 的调用将导致 Handler#正在调用handle(EventA a)。同样,在 EventB 对象上调用 accept 将导致调用 Handler#handle(EventB b)

关于java - 如何解决对全局设置/事件注册表的类型安全异议?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59964015/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com