The
basic theory
Bridging mode definition: separates the abstract part from its implementation so that they can all change independently. The
Bridging mode consists of 4 main roles:
(1) abstract class
(2) expands the abstract class
(3) Implements the class interface
(4) Implementing classes
based on the characteristics of the JavaScript language, we simplified it to 2 roles:
(1) extending the abstract class
(2) Concrete implementation class
How do you understand bridging mode? We then illustrate the idea of
bridging mode
Understanding bridging patterns, and the key is to understand the idea of separating the abstract and implementing parts. Let's illustrate the illustration
The simplest bridging mode
In fact, our most often used jquery each function is a typical bridging mode, we simulate its implementation as follows:
var each = function (arr, fn) {
for (var i = 0; i < arr.length; i++) {
var val = arr[i];
if (Fn.call (Val, I, Val, arr)) {
return false;
}
}
}
var arr = [1, 2, 3, 4];
Each (arr, function (i, v) {
Arr[i] = v * 2;
})
In this example, we loop through each function arr array, although this example is very common, but it contains a typical bridge mode.
In this example, the abstract part is the each function, which is the extended abstract class above, and the implementation part is FN, that is, the concrete implementation class. The abstract part and the implementation part can be changed independently. Although this example is simple, it is a typical application of bridging mode.
Bridging mode in plug-in development
One applicable scenario for bridging mode is component development. We usually develop components in order to adapt to different occasions, components corresponding to a number of different dimensions of the changes. Bridging mode can be applied to this, separating its abstraction from the implementation, making the component more scalable.
Let's say we want to develop a window widget, the window has different types: Ordinary message reminders, error reminders, each reminder is not the same way to display. This is a typical multidimensional variation of the scene. First we define two classes: the normal message window and the error message window.
function Messagedialog (animation) {
This.animation = animation;
}
MessageDialog.prototype.show = function () {
This.animation.show ();
}
function Errordialog (animation) {
This.animation = animation;
}
ErrorDialog.prototype.show = function () {
This.animation.show ();
}
These two classes are the abstract parts mentioned earlier, that is, the extended abstract class, which contains a member animation.
Both types of Windows are displayed through the Show method, but the animation effects are different. We define two types of effects that are displayed:
function Lineranimation () {
}
LinerAnimation.prototype.show = function () {
Console.log ("It is liner");
}
function Easeanimation () {
}
EaseAnimation.prototype.show = function () {
Console.log ("It is ease");
}
These two classes are specific implementation classes that implement specific display effects. So how do we call it?
var message = new Messagedialog (new Lineranimation ());
Message.show ();
var error = new Errordialog (new Easeanimation ());
Error.show ();
If we want to add an animation effect, you can define an effect class and pass it in.
Summarize
The key to learning bridging mode is to understand the separation between the abstract part and the realization part, so that the two can be changed independently, and not rigidly adhere to the form. JS plug-in flexible changes, the application of the changeable scene is very suitable for the use of this model to achieve. The most important thing to use in bridging mode is to find the different dimensions of the changes in the system.
deep understanding of the bridging pattern of JavaScript design patterns
Bridge mode is most commonly used in event monitoring, read a piece of code first:
Addevent (element, ' click ', Getbeerbyid);
function Getbeerbyid (e) {
var id = this.id;
Asyncrequest (' Get ', ' beer.uri?id= ' + ID, function (RESP) {
Callback Response.
Console.log (' Requested Beer: ' + resp.responsetext);
});
}
The above code, there is a problem is that Getbeerbyid must have the context of the browser to use, because the internal use of This.id this property, if no context, then the rest of the dish. Therefore, a slightly more experienced programmer will change the program into the following form:
function Getbeerbyid (ID, callback) {
Send the request by ID and return the data
Asyncrequest (' Get ', ' beer.uri?id= ' + ID, function (RESP) {
Callback response
Callback (Resp.responsetext);
});
}
It's more practical, isn't it? First, IDs can be passed in randomly, and a callback function is provided to customize the handler function. But what does this have to do with bridging? That's what the next piece of code is going to show:
Addevent (element, ' click ', Getbeerbyidbridge);
function Getbeerbyidbridge (e) {
Getbeerbyid (this.id, function (beer) {
Console.log (' Requested Beer: ' +beer);
});
}
The Getbeerbyidbridge here is the bridge we define to connect the abstract click event with the Getbeerbyid, and the ID of the event source, and a custom call function (Console.log output) is passed into the Getbeerbyid function as a parameter.
This example looks a little bit simpler, so let's take a more complex example of combat.
Combat XHR Connection Queue
We're going to build a queue in which there are many Ajax requests, and queues are used primarily to ensure that first-joined requests are processed first. At any time, we can pause requests, delete requests, retry requests, and support subscription events for individual requests.
Basic core Functions
Before we begin formally, we define a few of the core encapsulation functions, first, the function encapsulation of the asynchronous request:
var asyncrequest = (function () {
function Handlereadystate (o, callback) {
var poll = Window.setinterval (
function () {
if (o && o.readystate = 4) {
Window.clearinterval (poll);
if (callback) {
Callback (O);
}
}
},
50
);
}
var getxhr = function () {
var http;
try {
http = new XMLHttpRequest;
GETXHR = function () {
return to new XMLHttpRequest;
};
}
catch (e) {
var MSXML = [
' MSXML2. xmlhttp.3.0 ',
' MSXML2. XMLHTTP ',
' Microsoft.XMLHTTP '
];
for (var i = 0, len = msxml.length i < len; ++i) {
try {
http = new ActiveXObject (Msxml[i]);
GETXHR = function () {
return new ActiveXObject (Msxml[i]);
};
Break
}
catch (e) {}
}
}
return HTTP;
};
return function (method, Uri, callback, PostData) {
var http = getxhr ();
Http.open (method, Uri, true);
Handlereadystate (HTTP, callback);
Http.send (PostData | | null);
return HTTP;
};
})();
The encapsulated self execution function is a general-purpose AJAX request function that people who believe in attribute Ajax can read.
Next we define a common way to add a method (function):
Function.prototype.method = function (name, FN) {
This.prototype[name] = fn;
return this;
};
Finally, add 2 methods for the array, one for traversal and one for filtering:
if (! Array.prototype.forEach) {
Array.method (' ForEach ', function (FN, thisobj) {
var scope = Thisobj | | Window
for (var i = 0, len = this.length i < len; ++i) {
Fn.call (scope, this[i], I, this);
}
});
}
if (! Array.prototype.filter) {
Array.method (' Filter ', function (FN, thisobj) {
var scope = Thisobj | | Window
var a = [];
for (var i = 0, len = this.length i < len; ++i) {
if (!fn.call (scope, this[i], I, this)) {
Continue
}
A.push (This[i]);
}
return A;
});
}
Because some new browsers already support these two functions (or some libraries have already been supported), they should be judged first, and if they are already supported, they will not be processed.
Observer System
The observer plays an important role in the event process in the queue, and can subscribe to events when the queue is processed (successful, failed, pending):
Window. DED = window. DED | | {};
Ded.util = Ded.util | | {};
DED.util.Observer = function () {
This.fns = [];
}
DED.util.Observer.prototype = {
Subscribe:function (FN) {
This.fns.push (FN);
},
Unsubscribe:function (FN) {
This.fns = This.fns.filter (
Function (EL) {
If (El!== fn) {
Return el;
}
}
);
},
Fire:function (o) {
This.fns.forEach (
Function (EL) {
El (O);
}
);
}
};
Queue Main Implementation Code
First subscribe to the main attributes and event delegates for the queue:
DED. Queue = function () {
The queue that contains the request.
This.queue = [];
Use the observable object in 3 different states so that you can subscribe to events at any time
This.oncomplete = new DED.util.Observer;
This.onfailure = new DED.util.Observer;
This.onflush = new DED.util.Observer;
Core properties, which can be set when external calls are made
This.retrycount = 3;
this.currentretry = 0;
this.paused = false;
This.timeout = 5000;
This.conn = {};
This.timer = {};
};
Then, with the DED.Queue.method chain call, many of the available methods are added to the queue:
DED. Queue.
Method (' Flush ', function () {
Flush method
if (!this.queue.length > 0) {
Return
}
if (this.paused) {
this.paused = false;
Return
}
var that = this;
this.currentretry++;
var abort = function () {
That.conn.abort ();
if (that.currentretry = = That.retrycount) {
That.onFailure.fire ();
that.currentretry = 0;
} else {
That.flush ();
}
};
This.timer = Window.settimeout (abort, this.timeout);
var callback = function (o) {
Window.cleartimeout (That.timer);
that.currentretry = 0;
That.queue.shift ();
That.onFlush.fire (O.responsetext);
if (That.queue.length = = 0) {
That.onComplete.fire ();
Return
}
Recursive call to Flush
That.flush ();
};
This.conn = Asyncrequest (
This.queue[0][' method '],
this.queue[0][' URI '],
Callback
this.queue[0][' params ']
);
}).
Method (' Setretrycount ', function (count) {
This.retrycount = count;
}).
Method (' SetTimeout ', function (time) {
This.timeout = time;
}).
Method (' Add ', function (o) {
This.queue.push (o);
}).
Method (' Pause ', function () {
This.paused = true;
}).
Method (' Dequeue ', function () {
This.queue.pop ();
}).
Method (' Clear ', function () {
This.queue = [];
});
The code looks a lot, folded to find, in fact, is defined on the queue flush, Setretrycount, settimeout, add, pause, dequeue, and clear methods.
Simple Call
var q = new DED. Queue;
Set a higher number of retries to cope with slow connections
Q.setretrycount (5);
Set timeout time
Q.settimeout (1000);
Added 2 requests.
Q.add ({
Method: ' Get ',
URI: '/path/to/file.php?ajax=true '
});
Q.add ({
Method: ' Get ',
URI: '/path/to/file.php?ajax=true&woe=me '
});
Flush queues
Q.flush ();
Pause queue, remaining save
Q.pause ();
Empty.
Q.clear ();
Added 2 requests.
Q.add ({
Method: ' Get ',
URI: '/path/to/file.php?ajax=true '
});
Q.add ({
Method: ' Get ',
URI: '/path/to/file.php?ajax=true&woe=me '
});
Deletes the last request from the queue.
Q.dequeue ();
Flush again
Q.flush ();
What about the bridge?
There is no bridge in the calling code above, what about the bridge? Take a look at the complete example below and you'll find bridges everywhere:
<! DOCTYPE HTML PUBLIC "-//w3c//dtd HTML 4.01//en"
"Http://www.w3.org/TR/html4/strict.dtd" >
<html>
<head>
<meta http-equiv= "Content-type" content= "text/html; Charset=utf-8 ">
<title>ajax Connection queue</title>
<script src= "Utils.js" ></script>
<script src= "Queue.js" ></script>
<script type= "Text/javascript" >
addevent (window, ' Load ', function () {
Realize.
var q = new DED. Queue;
Q.setretrycount (5);
Q.settimeout (3000);
var items = $ (' items ');
var results = $ (' results ');
var queue = $ (' queue-items ');
Keep track of your requests on the client
var requests = [];
Subscribe to special processing steps after each request flush
Q.onflush.subscribe (function (data) {
results.innerhtml = data;
Requests.shift ();
queue.innerhtml = Requests.tostring ();
});
Subscription time processing steps
Q.onfailure.subscribe (function () {
results.innerhtml = ' <span style= ' color:red; >connection error!</span> ';
});
Subscribe to all successful processing steps x
Q.oncomplete.subscribe (function () {
results.innerhtml = ' <span style= ' color:green; >Completed!</span> ';
});
var actiondispatcher = function (Element) {
Switch (Element) {
Case ' flush ':
Q.flush ();
Break
Case ' dequeue ':
Q.dequeue ();
Requests.pop ();
queue.innerhtml = Requests.tostring ();
Break
Case ' pause ':
Q.pause ();
Break
Case ' Clear ':
Q.clear ();
requests = [];
queue.innerhtml = ';
Break
}
};
var addrequest = function (Request) {
var data = Request.split ('-') [1];
Q.add ({
Method: ' Get ',
URI: ' bridge-connection-queue.php?ajax=true&s= ' + data,
Params:null
});
Requests.push (data);
queue.innerhtml = Requests.tostring ();
};
Addevent (items, ' click ', Function (e) {
var e = e | | window.event;
var src = E.target | | E.srcelement;
try {
E.preventdefault ();
}
catch (ex) {
E.returnvalue = false;
}
Actiondispatcher (src.id);
});
var adders = $ (' adders ');
Addevent (adders, ' click ', Function (e) {
var e = e | | window.event;
var src = E.target | | E.srcelement;
try {
E.preventdefault ();
}
catch (ex) {
E.returnvalue = false;
}
Addrequest (src.id);
});
});
</script>
<style type= "text/css" media= "screen" >
Body
{
font:100% Georgia,times,serif;
}
H1, H2
{
Font-weight:normal;
}
#queue-items
{
Height:1.5em;
}
#add-stuff
{
padding:. 5em;
Background: #ddd;
border:1px solid #bbb;
}
#results-area
{
padding:. 5em;
border:1px solid #bbb;
}
</style>
</head>
<body id= "Example" >
<div id= "Doc" >
<h1>
Asynchronous join Request </h1>
<div id= "Queue-items" >
</div>
<div id= "Add-stuff" >
<h2> add a new request to the queue </h2>
<ul id= "Adders" >
<li><a href= "#" id= "action-01" > Add "01" to queue </a></li>
<li><a href= "#" id= "action-02" > Add "02" to queue </a></li>
<li><a href= "#" id= "action-03" > Add "03" to queue </a></li>
</ul>
</div>
<h2> Queue Control </h2>
<ul id= ' Items ' >
<li><a href= "#" id= "Flush" >Flush</a></li>
<li><a href= "#" id= "Dequeue" > Out dequeue</a></li>
<li><a href= "#" id= "pause" > Suspend pause</a></li>
<li><a href= "#" id= "clear" > Empty clear</a></li>
</ul>
<div id= "Results-area" >
<h2>
Results:
</h2>
<div id= "Results" >
</div>
</div>
</div>
</body>
</html>
In this example, you can do flush queues, pause queues, delete requests in queues, empty queues, and so on, and believe that you also feel the power of bridging.
Summary
The advantages of bridging mode are also obvious, and we only cite a few main advantages:
Separating the interface from the implementation part, an implementation is not necessarily bound to an interface, abstract class (function) implementation can be configured at runtime, an object can even change its implementation at runtime, with the abstraction and implementation of the full decoupling, but also conducive to layering, resulting in a better structured system.
Increase scalability
Implementation details are transparent to the customer and can hide implementation details from the customer.
Bridge mode also has its own disadvantages:
A large number of classes will lead to an increase in development costs and may also decrease in performance.