2

我有一个抽象类:

public abstract class AbstractCommand {

    private static State state;
}

意图

  • 类的对象State由一些“控制类”提供,提供每个AbstractCommand子类所需的数据
  • 每个子类都需要对其进行读取访问
  • 子类不允许更改字段

目前的方法

该字段state应由程序的“控制类”初始化,以便子类(定义命令)可以使用它(只读)。子类是内部定义的,应该用作用户的接口。此用户不应具有对 的写入权限state

问题

  • 在其中添加一个公共setState()方法AbstractCommand将使所有子类都可以访问它,并且用户也可以访问它
  • 使字段最终将强制对象的创建发生在抽象类中,并且“控制类”将不得不使用该对象,而且它是不可替换的

你如何处理这样的事情?

再试一次

因为一些答案建议使用包可见性的解决方案,所以我想知道这是否会做得很好:

通过将来自“控制类”(来自包外部)的调用委托给抽象类,在同一包中拥有一个提供所需信息的类。

听起来也有点模糊,但你怎么看?

4

7 回答 7

1

如果我理解正确,您正在寻找protected关键字。

在 java 中,此关键字允许子类和包字段访问,但不公开该字段。这允许您在不牺牲该领域的公共保护的情况下寻找您正在寻找的公共只读行为。唯一可以直接访问受保护字段的类将是同一包中的任何内容或直接子类(可能位于不同的包中)。

来源:http ://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

于 2013-01-17T16:16:50.537 回答
1

我只能提供模糊的解决方案。

先说一些解决方案:

要么做

private static final State state = Controller.initState();

或者使用控制反转,依赖注入,@Inject. 这也将允许单元测试。网络上肯定有开源 DI 容器(Spring,还是 Pico 容器还在?)。或者从一些 DI 容器中请求 bean。

如果两者都为时过早,请进行惰性评估(部分静态初始化已经是惰性的)。有时会看到一个内部类:

private static class Singleton {
    private static final State state = Controller.initState();
}

可能使用 getInstance。

我的选择:

不知何故没有静态,而是单例的吸气剂。一个 bean 框架与控制器一起工作。


单例而不是静态。

在之前的 eclipse 3 富客户端中大量使用的静态(静态函数),比如

IPreferenceStore store = IDEWorkbenchPlugin.getDefault().getPreferenceStore();
boolean autoPrint = store.getBoolean(AUTO_PRINT);

现在可以通过 OSGi 容器和注解进行依赖注入:

@Inject @Preference(AUTO_PRINT)
boolean autoPrint;

来自:Eclipse 4,M. Teufel 和 J. Helming 的 Rich Clients

除了更短之外,类之间的耦合更少,单元测试更容易编写,因为我们可以随心所欲地填写 autoPrint ,而不需要干预填充类。

如果有人犹豫添加这样一个容器的开销,最简单的方法是有几个静态的替代方案是拥有一个全局应用程序上下文,您可以在其中查找 java 对象,POJO bean。也许由 XML 文件支持:

State state = ApplicationContext.lookup(State.class, "state");

<bean name="state" class="org.anic.State" value="sleepy" depends="firstThis"/>
<bean name="firstThis .../>

请注意,不再需要静态

Spring 框架有这样一种 XML 方法。

优点是集中初始化,可以考虑顺序和不同的工厂/创建方法。

(对不起,混乱的答案。)

于 2013-01-17T16:45:12.383 回答
1

您可以将AbstractCommand“控制类”和特定实现放入同一个包中,并将其放入另一个包中。然后你可以提供一个包私有的 setter 和 protected getter。这将允许控制类设置值,并且实现只能访问 getter。

然而,这会弄乱你的包结构。如果您不希望这种情况发生 - 尝试使用工厂。您可以构建以下包结构:

 command
     impl
         CommandImpl1 //extends AbstractCommand
         CommandImpl2 //extends AbstractCommand
     AbstractCommand
     CommandFactory

这个想法是工厂用于创建 AbstractCommand 的实例。因此,您将在任何其他包中将参数传递给 Factory,它会选择您需要的实现并返回一个新对象。在这种情况下,您可以使用前面的想法来授予对 getter 和 setter 的适当访问权限。但是,在这里您将能够设置该字段一次且永远。

如果您需要多次修改它,您可以创建一个评估器。这是与 AbstractCommand 在同一个包中的 CommandAccessor 类,它应该提供如下静态方法:

public static void setState(State newState, AbstractCommand command);

没有什么可以阻止您在实现类中使用它,但是您可以设置一个不应该使用它的非正式规则。

于 2013-01-17T16:22:52.120 回答
0
public abstract class AbstractCommand {
    private static State state;
    static {
        state = Controller.getState();
    }
    protected AbstractCommand(){
    }        
    public State getState(){
        return state;
    }
}
于 2014-07-19T14:12:03.780 回答
0

将其作为抽象类的构造函数传入

public abstract class AbstractCommand {
    private static State state;
    protected AbstractCommand(State state){
        this.state = state;
    }        

    public State getState(){
        return state;
    }
}

在您的扩展课程中...

 public class Command1 extends AbstractCommand{
       public Command1(){
             super([some state]);
       }
 }

扩展类可以state在初始化期间设置一次,但此后具有只读访问权限。

于 2013-01-17T16:26:34.423 回答
0

所以我看到你想要 Magus 提到的行为“所以你希望 AbstractCommand 的子类不能设置状态值,但是另一个类可以做到吗?”

这是我的建议:

  1. 创建一个带有一些规则的接口。您想在所有子类中应用

  2. 现在让我们AbstractCommand实现该接口,它还应该包含state变量,通过这样做,您可以在较低级别维护一组规则

  3. 在第 1 步中定义的接口的第二站中,让您不想访问AbstractCommand类变量的其他类

通过这样做,您可以维护您的包结构。希望这可以帮助。

于 2013-01-17T16:31:32.963 回答
0

这是我正在尝试的:

创建接口为:

public interface RuleInterface { //Define rules here void method1(); }

现在在您的 AbstractCommand 类中实现它

public abstract class AbstractCommand implements RuleInterface{ private static String state; }

有其他类,这个类可以修改state变量

public class SubClassAbstractCommand extends AbstractCommand{ @Override public void method1() {
} }

为接口再创建一条腿:

public class AnotherLeg implements RuleInterface{ @Override public void method1() { } }

现在 AnotherLeg 类无法访问state变量,但您仍然可以通过接口强制执行规则RuleInterface

于 2013-01-17T17:07:54.207 回答