初始化抽象类的成员,没有具有写访问权限的子类

时间:2013-01-17 16:10:01

标签: java visibility encapsulation software-design

我有一个抽象类:

public abstract class AbstractCommand {

    private static State state;
}

意图

  • State的对象由一些"控制类"提供,提供每个AbstractCommand子类所需的数据
  • 每个子类都需要读取权限
  • 不允许子类更改字段

目前的方法

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

问题

  • setState()中添加公开AbstractCommand方法可以让所有子类都可以访问它,并将其发送给用户
  • 使字段成为最终将强制创建对象发生在抽象类和控制类"必须使用这个对象,而且它不可替换

你如何处理这样的事情?

另一次尝试

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

通过委派来自"控制类"的呼叫,在同一个包中提供一个提供所需信息的类。 (从包外面)到抽象类。

听起来有点模糊,但你觉得怎么样?

7 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:1)

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

但是,这会弄乱你的包结构。如果您不希望发生这种情况 - 请尝试使用Factory。您需要构建以下包结构:

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

这个想法是使用Factory来创建AbstractCommand的实例。因此,您将在任何其他包中将参数传递给Factory,它将选择您需要的实现并返回一个新对象。在这种情况下,您可以使用先前的想法授予对getter和setter的正确访问权限。但是在这里你可以永久地设置该字段。

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

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

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

答案 2 :(得分: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的富客户

除了缩短之外,类之间的耦合更少,单元测试可以更容易编写,因为我们可以像我们一样填写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方法。

优势是集中初始化,可以想象序列和不同的工厂/创建方法。

(抱歉这个杂乱的答案。)

答案 3 :(得分: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一次,但之后具有只读访问权限。

答案 4 :(得分:0)

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

这是我的建议:

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

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

  3. 在步骤1中界面定义的第二站中,您希望其他类不能访问AbstractCommand类变量

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

答案 5 :(得分:0)

以下是我的尝试:

创建界面:

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

现在在AbstractCommand类中实现它

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

有其他类,此类可以修改state varibale

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

为Interface创建另一条腿:

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

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

答案 6 :(得分:0)

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