首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >状态模式java

状态模式java
EN

Stack Overflow用户
提问于 2016-10-29 10:31:34
回答 3查看 3K关注 0票数 5

我正在学习java的设计模式。

我正在做一些链接,我正试着设计一台按状态排列的洗衣机

我对状态设计模式的实现有一个疑问。

代码语言:javascript
复制
public interface State {

   public void openLid();
   public void closeLid();
   public void start();
   public void stop();
   public void washing();
  } 

 public class Idle implements State{
 //implementing overidden methods
 .......

 }

 public class Washing implements State {
       //implementing overidden methods
       .......
  }


 public class WashingMachine {
   State state;

   public WashingMachine(State state) {
    this.state =  new Idle();
   }

  public State getState() {
    return state;
   }

   public void setState(State state) {
    this.state = state;
   }

 }

我想知道当在空闲状态之间切换到清洗实现时,可以通过网络看到两种方式。

1.WashingMachine类实现了状态接口,并根据某些条件将状态从Idle切换到,反之亦然。

2.以WashingMachine为成员变量的Idle洗涤类。

请任何一个人都可以建议我有点困惑的执行部分。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-10-29 12:28:49

在回答您的问题之前,我更愿意回顾一下模式的概念,并建议您对代码进行一些小小的修改。

状态模式允许对象在其内部状态发生变化时更改其行为。

在您的例子中,空闲和洗涤是很好的候选状态,而WashingMachine是承载状态对象的好候选人。

然而,有三点意见:

( 1)状态提供的方法应该是一些实现因对象的状态不同而不同的动作。

在你的声明中:

代码语言:javascript
复制
public interface WashingMachineState {    
   public void openLid();
   public void closeLid();
   public void start();
   public void stop();
   public void washing();
  } 

washing()不是一种行为,而是一种状态。

start()操作将状态从空闲更改为清洗。

在状态模式中,--具有状态的对象--命名为--上下文。

在您的例子中,上下文是WashingMachine

2)在状态模式中,语境要根据当前状态进行行为变化的动作。

为此,上下文将其处理委托给其当前状态实例。

它避免了上下文中的许多if - else (对于每个处理),并且它还允许降低上下文的复杂性,因为当您使用状态模式时,您会得到一系列行为:

  • 当我们处于空闲状态时,行为位于IdleState类中。
  • 当我们处于洗涤状态时,行为发生在WashingState类中。
  • 所以对于..。

要执行这些操作,状态实例需要上下文(WashingMachine)。

为了解决这个问题,你有两种方法:

或者将WashingMachine对象存储为状态实例中的字段,或者在上下文WashingMachine对象将处理委托给状态时将其作为参数传递。

我建议你用无状态的方式。

因此,当对startWashing()实例调用WashingMachine操作时,WashingMachine实例应该通过传递自身(如state.startWashing(this) )将处理委托给state.startWashing()

状态应该作为参数提供一个WashingMachine

代码语言:javascript
复制
public interface WashingMachineState {    
   void openLid(WashingMachine machine);
   void closeLid(WashingMachine machine);
   void pushStartBtn(WashingMachine machine);
   void pushStopBtn(WashingMachine machine);
} 

3)实际上,您定义了两种状态:空闲状态和洗涤状态。

应该使用stopping状态来完成这些操作,因为机器上的某些操作(打开门,推动启动btn )当机器处于“正停止”状态时,有一个特定的行为。

注意,在只有两种状态的情况下,您可能还想知道模式是否相关。

现在我可以回答你的问题了。

我想知道当在空闲状态之间切换到清洗实现时,可以通过网络看到两种方式。 1.WashingMachine类在一定条件下实现状态接口,并将状态从空闲切换到清洗或切换。 2.空闲和清洗类以WashingMachine作为成员变量。

WashingMachineWashingMachineState是合作的,但却是不同的。

所以他们不需要依赖相同的界面。

WashingMachine对象添加为状态子类的字段是可能的。

如前所述,您还可以将WashingMachine作为State方法的参数传递。

请注意,执行从状态到另一状态的切换的不是直接的WashingMachine

这是由政府执行的。

州应该调用WashingMachine.changeState()来执行它。

WashingMachine可以是:

代码语言:javascript
复制
public class WashingMachine {

   private WashingMachineState state;

   public WashingMachine() {
     this.state =  new Idle();
   }        

   protected void changeState(WashingMachineState state) {
     this.state = state;      
   }

   public void openLid(){
     state.openLid(this);
   } 

   public void closeLid(){
     state.closeLid(this);         
   } 
   public void pushStartBtn(){
     state.pushStartBtn(this);
   } 

   public void pushStopBtn(){
     state.pushStopBtn(this);
   } 

   public State getState() {
      return state;
   }

 }

关于修改WashingMachine的说明:

  • 当使用状态模式时,changeState作为setState更有意义。
  • changeState(State)可以使用protected修饰符来降低该方法的可见性,当然状态子类应该在与WashingMachine相同的包中。这是一个在Java中启用的实现细节。当然,对于其他OOP语言,您还有其他选择。

关于从空闲切换到清洗,我认为只有在调用IdleState状态时才有可能调用pushStartBtn()

以下是一个例子:

代码语言:javascript
复制
public class IdleState implements State {    
   public void openLid(WashingMachine machine){
       ...
   }
   public void closeLid(WashingMachine machine){
       ...
   }
   public void pushStartBtn(WashingMachine machine){
      //do processing with machine to begin effectively the washing
         ...
      machine.changeState(new WashingState());
   }

   public void pushStopBtn(WashingMachine machine){
       ...
   }
 } 
票数 6
EN

Stack Overflow用户

发布于 2016-10-29 10:48:28

我认为更好的选择是

代码语言:javascript
复制
public enum State{IDLE,WASHING};

然后用这个。这个enum甚至可以被命名为WashingMachineState,因为您提到的状态仅指定给洗衣机--它们不会被重用,所以这里没有接口。

如果您希望在不同的设备之间共享相同的状态,例如。WashingMachineDishWasher然后你可以用

代码语言:javascript
复制
public interface Statefull{
   public State getState();
   public void changeState(State newState);
}

并让WashingMachineDishWasher实现Statefull接口。使用Java 8的默认接口实现,您甚至可以在接口中包括getter实现,这样在实现类中就没有样板代码。

票数 1
EN

Stack Overflow用户

发布于 2016-10-29 10:47:41

好吧,让我们谈谈你的两个想法:

1.)洗衣机是个状态吗?不,绝对不是。那么它为什么需要实现状态接口呢?

2.)这几乎是可行的,但它使状态不可重用(对于这样的小型实现来说,这样的实现并不坏,但是对于像游戏这样的东西,它是很糟糕的)。它们只能是洗衣机的状态。如果我想用这些州做洗碗机呢?

你应该做的是:

创建一个接口或类,类似于StateManager,并使WashingMachine实现这个功能,然后在状态中创建一个StateManager字段,而不是使用一个具体的类。

示例:

代码语言:javascript
复制
public abstract class StateManager {
    public State state;

    public void setState(State newState) {
        state = newState;
        newState.parent = this;
    }
    public State getState() {
        return state;
    }
}

状态:

代码语言:javascript
复制
public abstract class State {
    public StateManager parent;
    // Whenever you want to set the object's state, use this
}

国家实例:

代码语言:javascript
复制
public class WashingState extends State {
    // your methods here
}

状态管理器示例:

代码语言:javascript
复制
public class WashingMachine extends StateManager {
    // your methods here.
}

我更改了所有zo类,而不是接口,因为它们使创建某些对象更容易(比如,如果您想要制造洗碗机和洗衣机,那么您可以从它们中提取洗涤部分,并为其创建一个单独的类)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40318196

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档