【问题标题】:How do I represent static constants that are derived at run time?如何表示在运行时派生的静态常量?
【发布时间】:2023-04-01 18:41:02
【问题描述】:

我有senderAsenderB 都实现sender 和两个单例,我有一个SenderWrapper(它可能实现ISenderWrapper)类,我想代表SenderA 和@987654327 @ 作为某种静态常量。

我正在获取实例,senderAsenderB 在运行时使用 Guice

我在运行时创建了许多 SenderWrapper 类的实例(每个请求一个),我想以某种方式在这些类中表示 senderAsenderB。我将在SenderWrapper 中定义的一些方法中使用它们。

我有几个解决方案:

  1. 我有两个非静态字段senderAsenderB,我从构造函数传递它们。 (也许我也可以注入它们,但我担心性能)

  2. 我可以拥有senderAsenderB静态 字段,并在运行时在Guice 模块中设置它们。但问题是这些字段不会是 const 并且会发送错误消息,表明它可以在运行时更改。

public class SenderWrapper implements ISenderWrapper {
    
    public static Sender senderA = null;
    public static Sender senderB = null;

    public void dummyMethod() {
        senderA.send(); senderB.send();
    }

}
    
//in Guice module
@Provides
public providesSenderA(){
    Sender senderA = new SenderA();
    SenderWrapper.senderA = senderA;
    return senderA;
}

  1. 我当前的解决方案是使用Enum 类来表示senderAsenderB。像
enum Senders {
senderA, senderB
}

我感觉这类似于第 2 点中提到的解决方案,至少在功能上是这样。我只是讨厌使用枚举。

解决这种情况最好、最优雅的方法是什么?我不介意重构,某种程度的间接来解决这个问题。

【问题讨论】:

  • 使用枚举——一般来说,与你的问题无关——是你能做的最好的事情之一。在 Java 中,它们非常强大且易于使用,具有类类功能。而且您的 IDE 可以为您生成大量代码并检查不一致之处,您必须使用任何其他方式自行检查。
  • 我不明白解决方案 2 的工作原理。请澄清。
  • @JayC667 编辑以提供示例
  • 好的,我明白了。您可以使用它,但您必须自己初始化它或设置一些规则。我不了解 Guice,因此无法告诉您如何正确地依赖注入静态字段。仅供参考:我认为“静态”比“最终”更多是注入的问题,因为如果你有final X x;,你可以“总是”稍后通过反射(思想缓存和 JVM 实现)设置 x,所以依赖注入框架/modules 将利用它。
  • 如果您已经使用了 guice,那么额外的开销不是主要问题(如果有疑问,请衡量)。考虑使用一个返回 a 或 b 的提供程序。

标签: java oop guice dropwizard


【解决方案1】:

为什么没有像这样的枚举(稍微重命名,所以我们知道它是枚举,而不是类):

enum SenderType {
    SENDER_A, SENDER_B
}

然后让你的班级像这样:

public abstract class SenderBase {

    public final SenderType myType;
    
    public SenderBase(SenderType pType) {
        myType = pType;
    }
    
    // optional getter
    public SenderType getType() {
        return myType;
    }
    
    public void send() {
        // here, send myType to socket. 
        // best is to send myType.name(), because ordinal WILL change when you re-order the enums in their enum class.

        // or, if you have different send() implementations for A and B, make this method abstract (and empty, remove body) so you FORCE A and B to implement it.
    }
    
}

你的类实现是这样的:

class SenderA extends SenderBase { 
    public SenderA () {
        super(SenderType.SENDER_A);
    }
}

class SenderB extends SenderBase {
    public SenderB () {
        super(SenderType.SENDER_B);
    }
}

并通过以下方式构造:

SenderA senderA = new SenderA();
SenderB senderB = new SenderB();

和你的包装器:

public abstract class SenderWrapper {

    public final SenderA mySenderA;
    public final SenderB mySenderB;
    
    public SenderWrapper() {
        mySenderA = new SenderA();
        mySenderB = new SenderB();
    }
    
    public void send() {
        mySenderA.send();
        mySenderB.send();
    }
    
}

实际上,现在我想到了 Wrapper,它甚至可能有一个 (Array)List,您可以在其中添加所有实现,并在 send() 中迭代它们。

【讨论】:

  • 我认为您忘记了难题中最重要的部分,即SenderWrapper,其中有senderAsenderB 的实例。我该如何表示?
  • 更新了我的答案。现在要出发去旅行,至少要到明天才能回答。
  • 这种方法的问题是,它不尊重senderAsenderB 是单例的事实
  • 好吧,然后在上面实现你的单例策略,这真的很容易......有多种简单的解决方案都可以轻松适应我的方法。
  • 不。我认为在它之上实现单例策略并不简单。你能建议怎么做吗?您最终将列出我的三个现有解决方案之一(我不想使用)
【解决方案2】:

答案竟然是匿名类。

在我的 Guice 模块中,我这样做:

//in Guice module
@Provides
public providesSenderWrapper(final SenderA senderA, final SenderA, senderB){
    return new ISenderWrapper {

        @Override
        public Send() {
            senderA.send(); senderB.send();
        }
    }
}

在类中拥有有效常量的巧妙方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多