Some basic custom message mechanisms have been studied, which is sufficient for some simple development.
Now let's try to face some slightly more complex architecture designs.
First, a plug-in mode is added:
Plugs
var plugs=(function(){ function addPlugs(name,plug) { var __plugs=this.__plugs=this.__plugs || {}; if(name && plug) { __plugs[name]={ installed:false, instance:plug }; } } function installPlugs() { var plugs=this.__plugs=this.__plugs || {}; for(var i in plugs) { var plug=plugs[i]; if(!plug.installed) { plug.instance.install(this); plug.installed=true; } } } return { ini:function(X) { X=monitor.ini(X); if(X.live) { var proto=X.prototype; proto.addPlugs=addPlugs; proto.installPlugs=installPlugs; } X.__plugs={}; X.addPlugs=addPlugs; X.installPlugs=installPlugs; } }})();
If you have read the first two pieces of code, this piece of code is easy to understand. It first binds the monitor mode to the input object (or function), and then adds two methods for the object: addplugs, installplugs
Addplugs add plug-in
Installplugs installation plug-in
Adding a plug-in is simple. You only need to add the object to a {} key-value pair.
After installing the plug-in, the install method of each plug-in object will be called.
Why is there a plug-in mode? Here is an example.
Create a requirement:
1. on the page, the tortoise and the rabbit race will be animated
2. rabbits and turtles can talk.
3. show their game process
I have nothing to do here. I just want to show you the program design.
The first step is to construct an animal function as a class for rabbits and turtles. The Code is as follows:
Animal
/// Animal function animal (config) {Config = config | |{}; var othis = this; this. name = config ["name"] | "anonymous"; this. X = config ["X"] | 0; var toward = 1; // right: 1, left-1 VaR _ timeout = 0; VaR _ speed = 5; // This. say = function (STR) {This. trigger ({type: "say", MSG: Str}); Return STR ;}// stop this. stop = function () {cleartimeout (_ timeout); this. trigger ({type: "Stop", X: This. x}); return this. x;} // run this. run = function (speed) {_ speed = speed | _ speed; this. X + =__ speed * toward; _ timeout = setTimeout (function () {othis. run ();}, 100); this. trigger ({type: "run", X: This. x, toward: Toward, speed :__ speed}); Return {X: This. x, toward: Toward, speed :__ speed};} // turn left this. turnleft = function () {toward =-1; this. trigger ({type: "Turn", toward: Toward}); Return toward;} // turn this. turnright = function () {toward = 1; this. trigger ({type: "Turn", toward: Toward}); Return toward ;}}
Now we have an animal class (animal), which has some behaviors: Say (say), stop (STOP), run (run), turn (turnleft), right (turnright)
Because I used the trigger method in the code, let's first use the previous article about monitor and initialize it:
monitor.ini(Animal);
In the second step, we first write a record function to record the words and deeds of an animal object. Here we only record the messages of say, stop, and turn. The Code is as follows:
View
Code
/// Recorder function logger () {This. DOM = document. getelementbyid ("log");} logger. prototype = {log: function (STR) {var time = new date (); this. dom. innerhtml + = "<br/>" + STR + '<span style = "color: Gray"> (' + time. gethours () + ":" + time. getminutes () + ":" + time. getseconds () + ") </span>" ;}, handler: function (data, p) {Switch (data. type) {Case "say": This. log (P. name + "said:" + data. MSG); break; Case "stop": This. log ('<span style = "color : Green "> '+ P. name + "STOPPED" + data. X + '</span>'); break; Case "Turn": This. log (P. name + "switched to" + (data. toward = 1? "Right": "Left"); break ;}}}
Here we use a page element (DIV) of ID = log to show the animal's words and deeds.
Step 3: Create the rabbit and Tortoise objects:
VaR hare = new animal ({name: "rabbit"}); var tortoise = new animal ({name: "Turtle "});
Step 4: bind the recorder to two objects.
If you want to bind to all animal objects, you can use the live method mentioned in the previous article. Here, we want to explain why plug-ins should be used. If live is not allowed, we need to create other animals, logger does not need to record these non-leading behaviors. Write the following code:
View
Code
var log=new Logger(); hare.bind("say",log);hare.bind("stop",log);hare.bind("turn",log);tortoise.bind("say",log);tortoise.bind("stop",log);tortoise.bind("turn",log);
Now let's ask a question. If you look at it carefully, we find that there are between live and bind. For example, if there are 100 animal objects, we only need to record 50 animal behaviors, so how depressing we should be, and we need to write a lot of bind. If our animal has more than these behaviors, we have extended 100 behavior records for it, it would be too scary to write a row of BIND.
Well, to improve it, you may suggest using a function, for example:
View
Code
function bindLog(ani){ ani.bind("say",log); ani.bind("stop",log); ani.bind("turn",log);}bindLog(hare);bindLog(tortoise);
If there is only one or two such requirements, this is also good. So what about expansion? Write many, such as ten, similar to logger classes. They need to bind 100 animal, several, or all (live can be considered for all)
Assume that some of these ten classes need to bind each animal object to a separate object. For example, we write a class of display, which represents the animals displayed on the screen, then an animal object needs to correspond to a display
Soon we will find that we need to write many methods similar to bindlog. Such as binddisplay and bindrun are filled with our main code.
So what will we do if we use the plug-in to write in the beginning?
First, modify monitor. ini (animal); To plugs. ini (animal) to support the plug-in mode. Because the plug-in mode is bound to the monitor by default, we do not need to initialize the monitor again.
Then, in the prototype of logger, add the install method
View
Code
install:function(main){ main.bind("say",this); main.bind("stop",this); main.bind("turn",this);}
Modify the binding Code as follows:
View
Code
// Add and install the plug-in Var log = new logger (); Hare. addplugs ("log", log); tortoise. addplugs ("log", log); Hare. installplugs (); tortoise. installplugs ();
We changed a series of BIND into using addplugs first, and finally calling installplugs.
What are the advantages of doing so?
Your main code is clear and complete as follows:
View
Code
VaR hare = new animal ({name: "rabbit"}); var tortoise = new animal ({name: "Turtle "}); // recorder var log = new logger (); Hare. addplugs ("log", log); tortoise. addplugs ("log", log); Hare. installplugs (); tortoise. installplugs ();
In this way, you can quickly understand the relationship between objects and organize your code from a higher abstraction level, instead of having to worry about writing a bunch of binds, if you want to replace a logger, for example, if you change to a logger that only records the say, or you want to display the animal's words as bubbles on top of them.
When many components are assembled, this mode brings us great convenience.
More importantly:
Animal can be seen as a business logic, which is well separated from the display. In the test, we can easily call hare. run hare. so that we can build our JS programs at a higher abstraction level. For some complex businesses, we can focus on both the business and the division of labor and cooperation.
PS:
Someone may ask why addplugs is required and then installplugs instead of addplugs.
After the example is completed, I found this problem. This is my negligence. the inertial thinking allows me to use the plug-ins I actually use.
In fact, the plugs of my application also has some extension methods, such as getplug. In actual development, the install method of the plug-in will trigger a trigger message, etc.
The purpose is to know the existence of other plug-ins when installing some plug-ins.
Another reason is that it involves lazy loading. In addplugs, sometimes I will addplugs a configuration, or an abbreviation, and then there is a JS file they actually point to which it is not loaded at this time.
It will not load JS and create plug objects until installplugs. Therefore, when the plug-in configuration is ready, I request the corresponding JS file (for example, directly requesting a server to merge multiple JS compressed files)
Don't bother everyone.
My suggestion is that if you are interested in this programming method, you 'd better modify it according to your own situation before using monitor and plugs (of course, they can also solve some problems ).