Initialize member of abstract class without subcla

2019-07-17 20:56发布

I have an abstract class:

public abstract class AbstractCommand {

    private static State state;
}

Intention

  • An object of class State is provided by some "controlling classes", providing data that is needed by each AbstractCommand subclass
  • Each subclass needs read access to it
  • The subclasses are not allowd to change the field

Current approach

The field state should be initialized by the "controlling classes" of the program so that subclasses (that define commands) can use it (read-only). The subclasses are defined internally and should be used as an interface for the user. This user should not have write access to state.

The problem

  • Adding a public setState() method in AbstractCommand would make it accessible to all subclasses and with that to the user
  • Making the field final would force the creating of the object to take place in the abstract class and the "controlling classes" would have to use this object, furthermore it would not be replacable

How do you handle something like this?

Another try

Because some answers suggested solutions using package visibility I wonder if this would do a good job:

Have a class in the same package that provides the required information by delegating a call from the "controlling classes" (from outside the package) to the abstract class.

Sounds a little fuzzy, too but what do you think?

7条回答
淡お忘
2楼-- · 2019-07-17 21:07

So I see you want the behavior as mentioned by Magus as "So you want that subclasses of AbstractCommand can't set the state value, but an other class can do it ?"

Here is my suggestion:

  1. Create an Interface with some rules. That you want to apply in all your subclasses

  2. Now Let AbstractCommand implement that Interface and it should also contain state variable, by doing this you can maintain a set of rule at lower level

  3. In second leg of Interface define in step 1 have your other class that you want not to have access to AbstractCommand class variable

By doing this you can maintain your package structure. Hope this helps.

查看更多
小情绪 Triste *
3楼-- · 2019-07-17 21:11

You could put the AbstractCommand into the same package with the "controlling classes" and specific implementations to another package. Then you could provide a package-private setter and protected getter. This would allow the controlling classes set the value and implementations would only have access to the getter.

Howevery, this would mess your package structure. If you do not want this to happen - try to use a Factory. You culd build the following package structure:

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

The idea is that a Factory is used to create instances of an AbstractCommand. So you will pass the parameter to the Factory in any other package and it would select an implementation you need and return you a new object. In this case you could use the previous idea to grant proper access to the getters and setters. However here you would be able to set the field once and forever.

If you need to modify it many times, you could create an assessor. This is the CommandAccessor class in the same package as your AbstractCommand and it should provide the static methos like:

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

Nothing would prevent you from using it in the implementation classes, however you could just set an informal rule that it should no be used.

查看更多
倾城 Initia
4楼-- · 2019-07-17 21:12

Here is what I was trying:

Create Interface as:

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

Now implement this in your AbstractCommand class

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

Have other class, this class can modify state varibale

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

Create one more leg for Interface as:

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

Now AnotherLeg class can't access state variable but still you can enforce the rules via interface RuleInterface

查看更多
smile是对你的礼貌
5楼-- · 2019-07-17 21:15

Pass it in as the constructor of your abstract class

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

    public State getState(){
        return state;
    }
}

In your extending classes...

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

The extending class can set the state once during initialization, but has read-only access thereafter.

查看更多
手持菜刀,她持情操
6楼-- · 2019-07-17 21:23
public abstract class AbstractCommand {
    private static State state;
    static {
        state = Controller.getState();
    }
    protected AbstractCommand(){
    }        
    public State getState(){
        return state;
    }
}
查看更多
啃猪蹄的小仙女
7楼-- · 2019-07-17 21:24

If I understand you correctly, you are looking for the protected keyword.

In java this keyword allows for subclass and package field access, but does not make the field public. This allows for the public read-only behavior you're looking for without sacrificing the public protection of the field. The only classes that can access a protected field directly will be anything in the same package or a direct subclass (which may be in a different package).

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

查看更多
登录 后发表回答