Introduced
State mode allows an object to change its behavior when its internal state changes, and the object appears to modify its class.
Body
For example, as we normally download things, there are usually several states, such as preparation status (ReadyState), download status (downloadingstate), pause status (Downloadpausedstate), Download complete State (downloadedstate), Failure State (downloadfailedstate), that is, in each state can only do the current state can do things, and can not do other state can do.
Because state mode describes how downloads (Download) behave differently in each of these states. The key idea of this model is to introduce an abstract class called State (or a function in JS) to represent the download status, which declares a certain public interface for each state's subclass (inherited function). Each of its inheritance functions implements the behavior associated with a particular state, such as Downloadingstate and Downloadedstate, respectively, to implement the behavior of downloading and downloading. These behaviors can be maintained by download.
Let's implement one, first defining the state function as a prototype for other basic functions:
Copy Code code as follows:
var state = function () {
};
State.prototype.download = function () {
throw new Error ("This method must be overloaded!");
};
State.prototype.pause = function () {
throw new Error ("This method must be overloaded!");
};
State.prototype.fail = function () {
throw new Error ("This method must be overloaded!");
};
State.prototype.finish = function () {
throw new Error ("This method must be overloaded!");
};
We have defined 4 method interfaces for state prototypes, corresponding to downloads (download), pauses (pause), failures (fail), end (finish) so that child functions can be overridden.
Before writing a child function, we first write a readystate function so that the state can be passed to the first download state:
Copy Code code as follows:
var ReadyState = function (odownload) {
State.apply (this);
This.odownload = Odownload;
};
Readystate.prototype = new State ();
ReadyState.prototype.download = function () {
This.oDownload.setState (This.oDownload.getDownloadingState ());
After ready, you can start downloading, so set the state-fetching method in the download function
Console.log ("Start download!");
};
ReadyState.prototype.pause = function () {
throw new Error ("Haven't started downloading, can't pause!");
};
ReadyState.prototype.fail = function () {
throw new Error ("file has not started downloading, how can say failure!");
};
ReadyState.prototype.finish = function () {
throw new Error ("file has not started downloading, of course, can not end!");
};
The function receives an instance of the download maintenance function as an argument, download function is used to control the state of the Change and acquisition (similar to the central controller, let the external call), readystate rewrite the prototype download method to start the download. Let's go on to see the main functions of the download function:
Copy Code code as follows:
var Download = function () {
This.ostate = new ReadyState (this);
};
Download.prototype.setState = function (ostate) {
This.ostate = ostate;
};
Externally exposed four public methods for external invocation
Download.prototype.download = function () {
This.oState.download ();
};
Download.prototype.pause = function () {
This.oState.pause ();
};
Download.prototype.fail = function () {
This.oState.fail ();
};
Download.prototype.finish = function () {
This.oState.finish ();
};
Get various states, passing in the current this object
Download.prototype.getReadyState = function () {
Return to New ReadyState (this);
};
Download.prototype.getDownloadingState = function () {
Return to New Downloadingstate (this);
};
Download.prototype.getDownloadPausedState = function () {
Return to New Downloadpausedstate (this);
};
Download.prototype.getDownloadedState = function () {
Return to New Downloadedstate (this);
};
Download.prototype.getDownloadedFailedState = function () {
Return to New Downloadfailedstate (this);
};
The prototype of the download function provides 8 methods, 4 are the actions for the download state, and the other 4 are used to get the current four different states, all 4 of which receive this as an argument. That is, passing the download instance itself as a parameter to the state object that handles the request (ReadyState and the inherited function to be implemented later), which allows the state object to access the Odownlaod more than necessary.
Next, you continue to define the functions of 4 related states:
Copy Code code as follows:
var downloadingstate = function (odownload) {
State.apply (this);
This.odownload = Odownload;
};
Downloadingstate.prototype = new State ();
DownloadingState.prototype.download = function () {
throw new Error ("file is already downloading!");
};
DownloadingState.prototype.pause = function () {this.oDownload.setState (This.oDownload.getDownloadPausedState ());
Console.log ("Pause download!");
};
DownloadingState.prototype.fail = function () {this.oDownload.setState (This.oDownload.getDownloadedFailedState ());
Console.log ("Download failed!");
};
DownloadingState.prototype.finish = function () {
This.oDownload.setState (This.oDownload.getDownloadedState ());
Console.log ("Download complete!");
};
Downloadingstate's main concern is that the files that are already being downloaded cannot be downloaded again, and that other states can go on continuously.
Copy Code code as follows:
var downloadpausedstate = function (odownload) {
State.apply (this);
This.odownload = Odownload;
};
Downloadpausedstate.prototype = new State ();
DownloadPausedState.prototype.download = function () {
This.oDownload.setState (This.oDownload.getDownloadingState ());
Console.log ("Continue downloading!");
};
DownloadPausedState.prototype.pause = function () {
throw new Error ("has been paused, I have to suspend it!");
};
DownloadPausedState.prototype.fail = function () {this.oDownload.setState (this.oDownload.getDownloadedFailedState) ( ));
Console.log ("Download failed!");
};
DownloadPausedState.prototype.finish = function () {
This.oDownload.setState (This.oDownload.getDownloadedState ());
Console.log ("Download complete!");
};
The Downloadpausedstate function should note that downloads that have been paused cannot be paused again.
Copy Code code as follows:
var downloadedstate = function (odownload) {
State.apply (this);
This.odownload = Odownload;
};
Downloadedstate.prototype = new State ();
DownloadedState.prototype.download = function () {
This.oDownload.setState (This.oDownload.getDownloadingState ());
Console.log ("Download again!");
};
DownloadedState.prototype.pause = function () {
throw new Error ("The download is over, but also pause what?" ");
};
DownloadedState.prototype.fail = function () {
throw new Error ("All download successful, how will fail?") ");
};
DownloadedState.prototype.finish = function () {
throw new Error ("Download success, no longer for success!");
};
Downloadedstate function, the same as successful download, you can not set finish, you can only set the download status.
Copy Code code as follows:
var downloadfailedstate = function (odownload) {
State.apply (this);
This.odownload = Odownload;
};
Downloadfailedstate.prototype = new State ();
DownloadFailedState.prototype.download = function () {
This.oDownload.setState (This.oDownload.getDownloadingState ());
Console.log ("Try downloading again!");
};
DownloadFailedState.prototype.pause = function () {
throw new Error ("Failed download, can not pause!");
};
DownloadFailedState.prototype.fail = function () {
throw new Error ("All failed, I also failed!");
};
DownloadFailedState.prototype.finish = function () {
throw new Error ("Failed to download, certainly will not succeed!");
};
Similarly, the failure status of the Downloadfailedstate function cannot fail again, but it can be tried again with finished to download again.
Call the test code, it's very simple, we are in the HTML demo bar, first of all, jquery, and then there are 3 buttons to represent: Start the download, pause, download again. (Note that the results are viewed with Firebug in Firefox because of the Console.log method).
Copy Code code as follows:
<link type= "Text/css" rel= "stylesheet" href= "Http://www.cnblogs.com/css/style.css"/>
<title>state pattern</title>
<script type= "Text/javascript" src= "/jquery.js" ></script>
<script type= "Text/javascript" src= "Download.js" ></script>
<script type= "Text/javascript" src= "States/state.js" ></script>
<script type= "Text/javascript" src= "States/downloadfailedstate.js" ></script>
<script type= "Text/javascript" src= "States/downloadpausedstate.js" ></script>
<script type= "Text/javascript" src= "States/downloadedstate.js" ></script>
<script type= "Text/javascript" src= "States/downloadingstate.js" ></script>
<script type= "Text/javascript" src= "States/readystate.js" ></script>
<body>
<input type= "button" value= "Start Download" id= "Download_button"/>
<input type= "button" value= "Pause" id= "Pause_button"/>
<input type= "button" value= "re-download" id= "Resume_button"/>
<script type= "Text/javascript" >
var odownload = new Download ();
$ ("#download_button"). Click (function () {
Odownload.download ();
});
$ ("#pause_button"). Click (function () {
Odownload.pause ();
});
$ ("#resume_button"). Click (function () {
Odownload.download ();
});
</script>
</body>
Summarize
The use of state patterns is also particularly clear, with the following two points:
1. The behavior of an object depends on its state, and it must change its behavior according to the state at run time.
2. An operation contains a large number of branch statements, and these branch statements depend on the state of the object. The state is usually the representation of one or more enumerated constants.