2011-10-28 110 views
2

对于我正在实施的特定状态模式,我不确定最佳的OO设计方法应该如何。请考虑以下几点:使用状态模式解耦状态

public class World { 
    private Animal dog_; 
    private Animals cats_; 
    ….. 
    public void sendDogRequest(DogRequest request) { 
     dog_.sendRequest(request); 
    } 
    … 
    public Cat getCat(String catName) { 
     … 
     return cat; 
    } 
    ... 
} 

public class Animal<RequestType extends Request, StateType extends State> { 
    private State<StateType> currentState_; 
    …. 
    public void sendRequest(RequestType request) { 
     request.sendToState(currentState_); 
    } 
    public void setState(StateType state) { 
     currentState_ = state; 
    } 
} 

public class Dog extends Animal<DogState> { 
    … 
} 

public class DogState extends State { 
    public DogState(Dog dog) { 
    … 
    } 
    public void seeCat(Cat cat) { } 
} 

public class OnLeashState extends DogState { 
    public void seeCat(Cat cat) { 
     dog.setState(new BarkingState()); 
    } 
} 

public class OffLeashState extends DogState { 
    public void seeCat(Cat cat) { 
     dog.setState(new ChasingAfterAnimalState(cat)); 
     cat.sendRequest(new RunAwayRequest(cat)); 
    } 
} 

public interface Request<StateType extends State> { 
    public void sendToState(StateType state); 
} 

public class DogRequest extends Request<DogState> { } 

public class SeeCatRequest extends DogRequest { 
    private Cat cat_; 
    public SeeCatRequest(Cat cat) { 
     cat_ = cat; 
    } 
    public void sendToState(DogState state) { 
     state.seeCat(state); 
    } 
} 

public class Controller() { 
    public Controller(World model, View view) { 
     … 
    } 
    ... 
    public void catSelected(String catName) { 
     Cat cat = world.getCat(catName); 
     Dog dog = world.getDog(); 
     world.sendDogRequest(new SeeCatRequest(cat)); 
    } 
    … 
} 

我犹豫的面积是这里的字new,即惯例。例示与另一个国家的new SomeState(),或在Controller或另一个State内的new SomeRequest()。在我看来,这会产生国家与兄弟姐妹之间的高度耦合,以及ControllerState

的要求如下:

  1. 它必须是可以添加新的国家,例如添加SniffingState
  2. 它也必须有可能用新的替代现有的国家。例如,我应该能够用不同的OffLeashState替换OffLeachState,执行不同的操作。例如(由于某种原因,该代码将无法格式化):

    公共类OffLeachState2扩展DogState {
    公共无效seeCat(猫猫){
    如果(dog.knows(CAT)){
    //狗变为 “PlayWithCatState”
    //猫得到一个 “PlayWithDog” 要求
    }其他{
    //狗变为 “ChaseAnimalState”
    }
    }
    }

  3. 最后,必须记录World类中的所有更改。这意味着世界级的记录器正在跟踪正在发生的所有事情。这也是因为世界级是一个模型,并且必须启动一个notifyObservers()以便视图知道要做些什么。

我的问题是,国家,请求等应该存储在哪里?例如:

  1. Dog应该有状态“getters”吗?例如,dog.getBarkingState(),dog.getOnLeashState()等?这似乎是有道理的,但它并不能改变类别。也就是说,每次我添加一个新的DogState类时,我也必须确保Dog有一个吸气剂。此外,World不知道这些更改,因此它不记录它们也不通知观察者。

  2. 是否应该有一个名为DogStates的类,我可以运行DogStates.getBarkingState()?再一次,类似的问题与上述相同。

  3. 他们应该是World班的一部分吗?例如,world.setDogState(dog, world.getDogBarkingState()?这将解决记录/更新问题,但对World类负责太多。

  4. 它应该是它们的一些组合,例如world.setState(dog, dog.getBarkingState()?这可能会很好,但不能保证类型安全。例如,我可以传递一个Dog对象与CatState,它不知道区别。

解决方案#4似乎对我最好,但我想对此问题提出一些其他意见。

同样的问题适用于Request对象。我本来想通过这都与对象相关联,例如world.sendRequest(dog, DogRequests.SEE_CAT)字符串发送Request S,但我过不了猫对象作为参数。

非常感谢您的宝贵时间!

回答

0

1)这看起来像一个编程试题。在这种情况下,如果不确定要做什么,使用模式!因此,每个State都应该由StateFactory生成,并为Factory实例提供关于World的一些信息,以便它可以决定要创建哪个特定的State实例。

这里的日志记录的东西:

public class World implements StateChangeListener { 
    private Animal dog_; 
    private Animals cats_; 

    private final List<StateChangeListener> listeners = new ArrayList<StateChangeListener>(); 

    public World() { 
    listeners.add(this); 
    } 

    // Instead of sending DogRequests to Dogs via the sendDogRequest method: 
    public <RequestType extends Request> void sendRequest(
     Animal<RequestType, ?> animal, Request<RequestType> request) { 
    animal.sendRequest(request); 
    for(StateChangeListener listener : listeners) { 
     listener.stateChanged(animal, request); 
    } 
    } 

    public void stateChanged(Animal<?, ?> animal, State<?> state) { 
    // ... log here ... 
    } 
... 

这厂的东西(可能有点浮躁,仿制药可能无法正常工作; O)。

public enum LocationEnum { 
    HOME, PARK, POND, FOREST 
} 

public interface StateFactory<StateType extends State> { 
    State<StateType> create(Animal<StateType, ?> animal, Context context); 
} 

// Do stuff Dogs do. 
public class DogStateFactory<DogState> { 
    public State<DogState> create(Animal<DogState, ?>, Context context) { 
    if(context.currentAnimalLocation==LocationEnum.POND) { 
     return new IgnoreEverythingState(); 
    }else if(context.currentAnimalLocation==LocationEnum.HOME){ 
     return new PerpetualBarkState(); 
    }else { 
     return new FollowEveryCatState(); 
    } 
    } 
} 

public class Animal<RequestType extends Request, StateType extends State> { 
    private StateFactory<StateType> stateFactory; 
    private State<StateType> currentState_; 

    public void sendRequest(Request<RequestType> request) { 
    request.sendToState(currentState_); 
    } 

    // A specific animal knows what it wants to do, depending on it's current 
    // state and it's situational context. We don't want other animals 
    // to set the state for us. 
    public void determineState() { 
    currentState_ = stateFactory.create(this, new Context(...)); 
    // One might want to extend the messaging stuff in a way that 
    // the World instance can log this state change. 
    } 
} 

public class Dog extends Animal<DogRequest, DogState> { 
    public Dog() { 
    this.stateFactory = new DogStateFactory<DogState>(); 
    } 
} 

2)如果你想让世界知道一切都在它发生的事情,你可以代替国家制定者蒙山的消息,让世界的实例听取大家的状态变化。

+0

非常感谢您的及时回复!你介意包含一些代码作为例子吗?对于1,我的理解是它会涉及诸如'dogStateFactory.createBarkingState()'之类的东西?对于2,你会在设置新状态后放置'notifyWorld()'吗? –

+0

好的。让我们看看我的晚餐受损脑子吐出了什么......要编辑我的答案。 – chabicht

+0

谢谢!哦,也许我应该开始编写编程考试。 :)我想出了整个场景来隔离我在较大范围内遇到的问题。 –