简体   繁体   中英

Implementing the state pattern with Java and EclipseLink

I would like to implement the state pattern in java for the following scenario:

  • The whole story is persisted with EclipseLink

  • A Person has a SecurityState (= Security Level).

  • Depending on a persons previous SecurityState , an operation changeSecurityLevel (and probably other operations too) will have different behaviour.

Person Class

@Entity
public class Person extends DatabaseObject{
    // .... lots of properties....
    @ManyToOne(fetch=FetchType.LAZY)
    private SecurityState securityState;

    public changeSecurityState(SecurityState newState){
       securityState.changeSecurityState(newState);
    }  

}

SecurityState:

@Entity
public abstract class SecurityState extends DatabaseObject{
    private int level;   // 1 = low, 2 = medium, 3 = high
    private Person person;  

    public SecurityState(Person p){
        this.person = p;
    }

    public changeSecurityState(SecurityState newState){
       // not implemented
    }        

    public void someOtherOperation(){
    }

    // getter and setter

}

For example the HighSecurityState :

@Entity
public class HighSecurityState extends SecurityState {
    private int level = 3;

    public changeSecurityState(SecurityState newState){
        if(newState.getLevel() == 1){
           // do specific stuff for High-to-Low status changes

           person.securityState = new LowSecurityState();
        }else if(newState.getLevel() == 2){
           person.securityState = new MediumSecurityState();
        }else{ }
    }  
}

Questions: - Is the state-pattern more or less correctly implemented? I don't like the if-else somehow, this doesn't really feel right.

  • How can I persist the SecurityState? Which class/table should be persisted, the abstract SecurityState ? Or the concrete state classes?

Don't worry about if-else for such simple cases; it's fine.

Maybe switch looks a little better - but it's essentially the same thing

switch(newState.getLevel())
    case 1:
             ...
    case ...

    default: throw new AssertionError();

Or you could even go apply Visitor pattern - is it really worth it though?

public changeSecurityState(LowSecurityState newState)
...    
public changeSecurityState(MediumSecurityState newState)
...    
public changeSecurityState(HighSecurityState newState)
...

On the 2nd question - security state is just a simple int; you don't need a separate table for it; it should just be an integer column in the person table. You can make it an enum type in Java if you like.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM