class Document is field state: string // ... method publish() is switch (state) "draft": state = "moderation" break "moderation": if (currentUser.role == 'admin') state = "published" break "published": // 什么也不做。 break // ...
namespaceRefactoringGuru.DesignPatterns.State.Conceptual { // The Context defines the interface of interest to clients. It also // maintains a reference to an instance of a State subclass, which // represents the current state of the Context. classContext { // A reference to the current state of the Context. private State _state = null;
// The Context allows changing the State object at runtime. publicvoidTransitionTo(State state) { Console.WriteLine($"Context: Transition to {state.GetType().Name}."); this._state = state; this._state.SetContext(this); }
// The Context delegates part of its behavior to the current State // object. publicvoidRequest1() { this._state.Handle1(); }
publicvoidRequest2() { this._state.Handle2(); } } // The base State class declares methods that all Concrete State should // implement and also provides a backreference to the Context object, // associated with the State. This backreference can be used by States to // transition the Context to another State. abstractclassState { protected Context _context;
// Concrete States implement various behaviors, associated with a state of // the Context. classConcreteStateA : State { publicoverridevoidHandle1() { Console.WriteLine("ConcreteStateA handles request1."); Console.WriteLine("ConcreteStateA wants to change the state of the context."); this._context.TransitionTo(new ConcreteStateB()); }
classConcreteStateB : State { publicoverridevoidHandle1() { Console.Write("ConcreteStateB handles request1."); }
publicoverridevoidHandle2() { Console.WriteLine("ConcreteStateB handles request2."); Console.WriteLine("ConcreteStateB wants to change the state of the context."); this._context.TransitionTo(new ConcreteStateA()); } }
classProgram { staticvoidMain(string[] args) { // The client code. var context = new Context(new ConcreteStateA()); context.Request1(); context.Request2(); } } }
Output.txt: 执行结果
1 2 3 4 5 6 7
Context: Transition to ConcreteStateA. ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context. Context: Transition to ConcreteStateB. ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to ConcreteStateA.
在 C++ 中使用模式
复杂度: ★☆☆
流行度: ★★☆
使用示例: 在 C++ 语言中, 状态模式通常被用于将基于 switch语句的大型状态机转换为对象。
#include<iostream> #include<typeinfo> /** * The base State class declares methods that all Concrete State should * implement and also provides a backreference to the Context object, associated * with the State. This backreference can be used by States to transition the * Context to another State. */
/** * The Context defines the interface of interest to clients. It also maintains a * reference to an instance of a State subclass, which represents the current * state of the Context. */ classContext { /** * @var State A reference to the current state of the Context. */ private: State *state_;
public: Context(State *state) : state_(nullptr) { this->TransitionTo(state); } ~Context() { delete state_; } /** * The Context allows changing the State object at runtime. */ voidTransitionTo(State *state){ std::cout << "Context: Transition to " << typeid(*state).name() << ".\n"; if (this->state_ != nullptr) deletethis->state_; this->state_ = state; this->state_->set_context(this); } /** * The Context delegates part of its behavior to the current State object. */ voidRequest1(){ this->state_->Handle1(); } voidRequest2(){ this->state_->Handle2(); } };
/** * Concrete States implement various behaviors, associated with a state of the * Context. */
classConcreteStateA : public State { public: voidHandle1()override;
classConcreteStateB : public State { public: voidHandle1()override{ std::cout << "ConcreteStateB handles request1.\n"; } voidHandle2()override{ std::cout << "ConcreteStateB handles request2.\n"; std::cout << "ConcreteStateB wants to change the state of the context.\n"; this->context_->TransitionTo(new ConcreteStateA); } };
voidConcreteStateA::Handle1(){ { std::cout << "ConcreteStateA handles request1.\n"; std::cout << "ConcreteStateA wants to change the state of the context.\n";
Context: Transition to 14ConcreteStateA. ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context. Context: Transition to 14ConcreteStateB. ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to 14ConcreteStateA.
/** * Common interface for all states. */ publicabstractclassState { Player player;
/** * Context passes itself through the state constructor. This may help a * state to fetch some useful context data if needed. */ State(Player player) { this.player = player; }
// Context delegates handling user's input to a state object. Naturally, // the outcome will depend on what state is currently active, since all // states can handle the input differently. JButtonplay=newJButton("Play"); play.addActionListener(e -> textField.setText(player.getState().onPlay())); JButtonstop=newJButton("Stop"); stop.addActionListener(e -> textField.setText(player.getState().onLock())); JButtonnext=newJButton("Next"); next.addActionListener(e -> textField.setText(player.getState().onNext())); JButtonprev=newJButton("Prev"); prev.addActionListener(e -> textField.setText(player.getState().onPrevious())); frame.setVisible(true); frame.setSize(300, 100); buttons.add(play); buttons.add(stop); buttons.add(next); buttons.add(prev); } }
/** * The Context defines the interface of interest to clients. It also maintains a * reference to an instance of a State subclass, which represents the current * state of the Context. */ classContext { /** * @var State A reference to the current state of the Context. */ private$state;
/** * The base State class declares methods that all Concrete State should * implement and also provides a backreference to the Context object, associated * with the State. This backreference can be used by States to transition the * Context to another State. */ abstractclassState { /** * @var Context */ protected$context;
/** * Concrete States implement various behaviors, associated with a state of the * Context. */ classConcreteStateAextendsState { publicfunctionhandle1(): void { echo"ConcreteStateA handles request1.\n"; echo"ConcreteStateA wants to change the state of the context.\n"; $this->context->transitionTo(newConcreteStateB()); }
publicfunctionhandle2(): void { echo"ConcreteStateB handles request2.\n"; echo"ConcreteStateB wants to change the state of the context.\n"; $this->context->transitionTo(newConcreteStateA()); } }
Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateA. ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context. Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateB. ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateA.
from __future__ import annotations from abc import ABC, abstractmethod
classContext: """ The Context defines the interface of interest to clients. It also maintains a reference to an instance of a State subclass, which represents the current state of the Context. """
_state = None """ A reference to the current state of the Context. """
deftransition_to(self, state: State): """ The Context allows changing the State object at runtime. """
print(f"Context: Transition to {type(state).__name__}") self._state = state self._state.context = self
""" The Context delegates part of its behavior to the current State object. """
defrequest1(self): self._state.handle1()
defrequest2(self): self._state.handle2()
classState(ABC): """ The base State class declares methods that all Concrete State should implement and also provides a backreference to the Context object, associated with the State. This backreference can be used by States to transition the Context to another State. """
""" Concrete States implement various behaviors, associated with a state of the Context. """
classConcreteStateA(State): defhandle1(self) -> None: print("ConcreteStateA handles request1.") print("ConcreteStateA wants to change the state of the context.") self.context.transition_to(ConcreteStateB())
defhandle2(self) -> None: print("ConcreteStateB handles request2.") print("ConcreteStateB wants to change the state of the context.") self.context.transition_to(ConcreteStateA())
Context: Transition to ConcreteStateA ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context. Context: Transition to ConcreteStateB ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to ConcreteStateA
# The Context defines the interface of interest to clients. It also maintains a # reference to an instance of a State subclass, which represents the current # state of the Context. classContext # A reference to the current state of the Context. attr_accessor:state private :state
# @param [State] state definitialize(state) transition_to(state) end
# The Context allows changing the State object at runtime. deftransition_to(state) puts "Context: Transition to #{state.class}" @state = state @state.context = self end
# The Context delegates part of its behavior to the current State object.
defrequest1 @state.handle1 end
defrequest2 @state.handle2 end end
# The base State class declares methods that all Concrete State should implement # and also provides a backreference to the Context object, associated with the # State. This backreference can be used by States to transition the Context to # another State. classState attr_accessor:context
# @abstract defhandle1 raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end
# @abstract defhandle2 raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
# Concrete States implement various behaviors, associated with a state of the # Context.
classConcreteStateA < State defhandle1 puts 'ConcreteStateA handles request1.' puts 'ConcreteStateA wants to change the state of the context.' @context.transition_to(ConcreteStateB.new) end
defhandle2 puts 'ConcreteStateA handles request2.' end end
classConcreteStateB < State defhandle1 puts 'ConcreteStateB handles request1.' end
defhandle2 puts 'ConcreteStateB handles request2.' puts 'ConcreteStateB wants to change the state of the context.' @context.transition_to(ConcreteStateA.new) end end
Context: Transition to ConcreteStateA ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context. Context: Transition to ConcreteStateB ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to ConcreteStateA
在 Swift 中使用模式
复杂度: ★☆☆
流行度: ★★☆
使用示例: 在 Swift 语言中, 状态模式通常被用于将基于 switch语句的大型状态机转换为对象。
/// The Context defines the interface of interest to clients. It also maintains /// a reference to an instance of a State subclass, which represents the current /// state of the Context. classContext {
/// A reference to the current state of the Context. privatevar state: State
init(_state: State) { self.state = state transitionTo(state: state) }
/// The Context allows changing the State object at runtime. functransitionTo(state: State) { print("Context: Transition to "+String(describing: state)) self.state = state self.state.update(context: self) }
/// The Context delegates part of its behavior to the current State object. funcrequest1() { state.handle1() }
funcrequest2() { state.handle2() } }
/// The base State class declares methods that all Concrete State should /// implement and also provides a backreference to the Context object, /// associated with the State. This backreference can be used by States to /// transition the Context to another State. protocolState: class {
/// Concrete States implement various behaviors, associated with a state of the /// Context. classConcreteStateA: BaseState {
overridefunchandle1() { print("ConcreteStateA handles request1.") print("ConcreteStateA wants to change the state of the context.\n") context?.transitionTo(state: ConcreteStateB()) }
overridefunchandle2() { print("ConcreteStateB handles request2.") print("ConcreteStateB wants to change the state of the context.\n") context?.transitionTo(state: ConcreteStateA()) } }
/// Let's see how it all works together. classStateConceptual: XCTestCase {
functest() { let context =Context(ConcreteStateA()) context.request1() context.request2() } }
Output.txt: 执行结果
1 2 3 4 5 6 7 8 9
Context: Transition to StateConceptual.ConcreteStateA ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context.
Context: Transition to StateConceptual.ConcreteStateB ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context.
Context: Transition to StateConceptual.ConcreteStateA
funcstartTracking() { print("DisabledTrackingState: Received 'start tracking'") print("DisabledTrackingState: Changing state to 'enabled'...") tracker?.update(state: EnabledTrackingState(tracker: tracker)) }
funcpauseTracking(fortime: TimeInterval) { print("DisabledTrackingState: Pause tracking for \(time) seconds")
for i in0...Int(time) { print("DisabledTrackingState: pause...\(i)") }
print("DisabledTrackingState: Time is over") print("DisabledTrackingState: Returing to 'enabled state'...\n") self.tracker?.update(state: EnabledTrackingState(tracker: self.tracker)) self.tracker?.startTracking() }
funcstopTracking() { print("DisabledTrackingState: Received 'stop tracking'") print("DisabledTrackingState: Do nothing...") }
funcmakeCheckIn() { print("DisabledTrackingState: Received 'make check-in'") print("DisabledTrackingState: Changing state to 'enabled'...") tracker?.update(state: EnabledTrackingState(tracker: tracker)) tracker?.makeCheckIn() }
funcfindMyChildren() { print("DisabledTrackingState: Received 'find my children'") print("DisabledTrackingState: Changing state to 'enabled'...") tracker?.update(state: EnabledTrackingState(tracker: tracker)) tracker?.findMyChildren() } }
EnabledTrackingState: Received 'pause tracking' for 2.0 seconds EnabledTrackingState: Changing state to 'disabled'... DisabledTrackingState: Pause tracking for 2.0 seconds DisabledTrackingState: pause...0 DisabledTrackingState: pause...1 DisabledTrackingState: pause...2 DisabledTrackingState: Time is over DisabledTrackingState: Returing to 'enabled state'...
EnabledTrackingState: performing check-in at the current location
EnabledTrackingState: searching for children...
EnabledTrackingState: Received 'stop tracking' EnabledTrackingState: Changing state to 'disabled'... DisabledTrackingState: Received 'stop tracking' DisabledTrackingState: Do nothing...
/** * The Context defines the interface of interest to clients. It also maintains a * reference to an instance of a State subclass, which represents the current * state of the Context. */ classContext { /** * @type {State} A reference to the current state of the Context. */ privatestate: State;
/** * The Context allows changing the State object at runtime. */ publictransitionTo(state: State): void { console.log(`Context: Transition to ${(<any>state).constructor.name}.`); this.state = state; this.state.setContext(this); }
/** * The Context delegates part of its behavior to the current State object. */ publicrequest1(): void { this.state.handle1(); }
/** * The base State class declares methods that all Concrete State should * implement and also provides a backreference to the Context object, associated * with the State. This backreference can be used by States to transition the * Context to another State. */ abstractclassState { protectedcontext: Context;
/** * Concrete States implement various behaviors, associated with a state of the * Context. */ classConcreteStateAextendsState { publichandle1(): void { console.log('ConcreteStateA handles request1.'); console.log('ConcreteStateA wants to change the state of the context.'); this.context.transitionTo(newConcreteStateB()); }
publichandle2(): void { console.log('ConcreteStateB handles request2.'); console.log('ConcreteStateB wants to change the state of the context.'); this.context.transitionTo(newConcreteStateA()); } }
Context: Transition to ConcreteStateA. ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context. Context: Transition to ConcreteStateB. ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to ConcreteStateA.