1. Definition
The proxy pattern is to provide a surrogate or placeholder for an object , In order to control access to it .
The key to the agency model is , When the customer is inconvenient to directly access an object or does not meet the needs , Provide a surrogate object to control access to this object , The client is actually visiting a surrogate . After the stand in object does some processing to the request , And then pass the request to the ontology object .
2. Example
Xiao Hong gives Xiao Gang a gift
- Without proxy mode
var Gift = function(){};
var xiaohong = {
sendGift: function(target) {
var gift = new Gift();
target.receiveGift(gift);
}
}
var xiaogang = {
receiveGift: function(gift) {
console.log(' Receive a gift ' + gift)
}
}
xiaohong.sendGift(xiaogang);
Copy code
- Using the proxy pattern ( Xiao Hong sends Xiao Gang a gift through Xiao Ming )
var Gift = function(){};
var xiaohong = {
sendGift: function(target) {
var gift = new Gift();
target.receiveGift(gift);
}
}
var xiaoming = {
receiveGift: function(gift) {
xiaogang.receiveGift(gift)
}
}
var xiaogang = {
receiveGift: function(gift) {
console.log(' Receive a gift ' + gift)
}
}
xiaohong.sendGift(xiaogang);
Copy code
This is a simple proxy pattern . There seems to be no essential difference between the two , Introducing a proxy object just seems to complicate things . The proxy model here is really useless , Simply pass the request to the ontology .
Change the background of the above example : Xiao Gang accepted the gift and came with the change of mood
var Gift = function(){};
var xiaohong = {
sendGift: function(target) {
var gift = new Gift();
target.receiveGift(gift);
}
}
var xiaoming = {
receiveGift: function(gift) {
xiaogang.listenGoodMood(function(){ // Monitor Xiaogang's good mood
xiaogang.receiveGift(gift)
})
}
}
var xiaogang = {
receiveGift: function(gift) {
console.log(' Receive a gift ' + gift)
},
listenGoodMood: function(fn) {
setTimeout(function(){ // hypothesis 10 Seconds later A I feel better
fn()
}, 10000)
}
}
xiaohong.sendGift(xiaogang);
Copy code
3. Protect agents and virtual agents
3.1 Protection agency
agent “ Xiao Ming ” Can help “ Xiaogang ” Filter out some requests , For example, those who give gifts are too old , This request can be made directly in the agent “ Xiao Ming ” Was rejected . This agent is called “ Protection agency ”
3.2 Virtual agent
hypothesis new Gift() Is an expensive operation , You can put new Gift() Leave the operation to the agent “ Xiao Ming ” To carry out , agent “ Xiao Ming ” Will choose “ Xiaogang ” When you are in a good mood new Gift() . This is called “ Virtual agent ”. Virtual agents put some expensive objects , Delay creating it until you really need it .
var xiaoming = {
receiveGift: function(gift) {
xiaogang.listenGoodMood(function(){ // Monitor Xiaogang's good mood
var gift = new Gift(); // Delay creation gift object
xiaogang.receiveGift(gift)
})
}
}
Copy code
The protection agent is used to control the access of objects with different permissions to the target object , But in JavaScript It's not easy to implement a protection agent , Because you can't tell who accessed an object . Virtual agent is the most commonly used agent mode .
4. Virtual agent realizes picture preloading
If you give it to someone directly img Label node settings src attribute , Because the picture is too big or the network is not good , The position of the picture will be blank for some time . A common practice is to use one first loading Picture space , Then load the image asynchronously , When the image is loaded, fill it in img Node , This kind of scenario is very suitable for the use of virtual agents .
Examples are as follows :
First create an ontology object , This object is responsible for creating a img label , And provide an external setSrc Interface , The outside world calls this interface , You can give img Label settings src attribute :
var myImage = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc: function(src) {
imgNode.src = src;
}
}
})();
myImage.setSrc('http:// xxx.png');
Copy code
You can see , Before the picture is loaded , There is a period of blank space in the page .
Introduce proxy object proxyImage, Through this proxy object , Before the picture is actually loaded , A chrysanthemum diagram with space occupying will appear on the page loading.gif, To prompt the user that the picture is loading .
var myImage = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc: function(src) {
imgNode.src = src;
}
}
})();
var proxyImage = (function(){
var img = new Image;
img.onload = function(){
myImage.setSrc(this.src);
}
return {
setSrc: function(src) {
myImage.setSrc('file//xxx/loading.gif')
img.src = src;
}
}
})()
proxyImage.setSrc('http:// xxx.png')
Copy code
adopt proxyImage Indirect access to MyImage. proxyImage Control the customer's response to MyImage The interview of , And add some additional operations in the process , For example, before the real picture is loaded , The first img Node src Set as a local loading picture .
5. The meaning of agency
Some people may have questions , It's just a small picture preloading function , It can be done even without introducing any model , So what are the benefits of introducing the agent model ? Now let's get rid of the agent , Write a more common image preload function .
The preload image function without agent is implemented as follows :
var myImage = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
var img = new Image;
img.onload = function(){
imgNode.src = img.src;
}
return {
setSrc: function(src) {
imgNode.src = 'file//xxx/loading.gif';
img.src = src
}
}
})();
myImage.setSrc('http:// xxx.png')
Copy code
To illustrate the meaning of agency , Introduce a principle of object-oriented design -- Principle of single responsibility
The principle of single responsibility refers to , Just one class ( It usually also includes objects and functions ) for , There should be only one cause for it to change . If an object has multiple responsibilities , It means that this object will become huge , There may be several reasons for its change . Object oriented design encourages the distribution of behavior among fine-grained objects , If an object has too many responsibilities , It's like coupling these responsibilities together , This coupling can lead to fragile and low cohesion designs . When change happens , The design may be accidentally damaged .
Responsibilities are defined as “ The cause of the change ”. In the previous code MyImage In addition to being responsible for img Node set src Outside , Also responsible for preloading images . When dealing with one of these responsibilities , It is possible that its strong coupling affects the implementation of another responsibility .
actually , All we need is to give img Node set src, Preloading images is just a icing on the cake . If you can put this operation in another object , It's a very good way . The role of agency is reflected here , The agent is responsible for preloading images , After the preload operation is completed , Relinquish the request to the ontology MyImage.
We have not changed or increased MyImage The interface of , But through proxy objects , In fact, new behaviors have been added to the system . This is in line with the open - Closed principle . to img Node set src And image preloading , Isolated in two objects , They can change each other without affecting each other . And even if one day you don't need preloading , Just change to the request ontology instead of the request proxy object .
6. Consistency between proxy and local interface
In the previous example , If one day we no longer need preloading , Then the proxy object is no longer needed , You can choose to request the ontology directly . The key is that both proxy objects and ontologies provide setSrc Method , In the eyes of customers , Proxy objects and ontologies are consistent , The process of the agent taking over the request is transparent to the user , Users don't know the difference between agents and ontologies , There are two advantages to doing so .
- Users can safely request agents , He only cares about whether he can get the desired result
- In any place where ontologies are used, they can be replaced by using proxies .
stay Java Such as language , Both agents and ontologies need to explicitly implement the same interface , On the one hand, interfaces ensure that they will have the same methods , On the other hand , Interface oriented programming caters to the principle of dependency inversion , Upward transformation through the interface , To avoid compiler type checking , Agents and ontologies can be replaced in the future .
If both the proxy object and the ontology object are a function ( Functions are also objects ), All functions must be executable , It can be considered that they also have the same “ Interface ”,
var myImage = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return function(src) {
imgNode.src = src;
}
})();
var proxyImage = (function(){
var img = new Image;
img.onload = function(){
myImage(this.src);
}
return function(src){
myImage('file//xxx/loading.gif');
img.src = src;
}
})();
proxyImage('http:// xxx.png');
Copy code
7. Virtual agent merge HTTP request
var synchronousFile = function(id) {
console.log(' Start syncing files ,id by :' + id);
}
var proxySynchronousFile = (function(){
var cache = [],
timer;
return function(id) {
cache.push(id);
if(timer) {
return;
}
timer = setTimeout(function(){
synchronousFile(cache.join(','));
clearTimeout(timer);
timer = null;
cache.length = 0;
}, 2000)
}
})()
var checkbox = document.getElementsByTagName('input');
for(var i=0,c; c=checkbox[i++];){
c.onclick = function(){
if(this.checked === true) {
proxySynchronousFile(this.id);
}
}
}
Copy code
8. Application of virtual agent in lazy loading
var miniConsole = (function(){
var cache = [];
var handler = function(ev){
if(ev.keyCode === 113){ // When the user presses F2 when , Start loading real miniConsole.js
var script = document.createElement('script');
script.onload = function(){
for(var i=0, fn; fn=cache[i++];) {
fn();
}
}
script.src = 'miniConsole.js';
document.getElementsByTagName('head')[0].appendChild(script);
document.body.removeEventListener('keydown', handler); // Load only once miniConsole.js
}
}
document.body.addEventListener('keydown',handler, false);
return {
log: function(){
var args = arguments;
cache.push(function(){
return miniConsole.log.apply(miniConsole, args)
})
}
}
})()
miniConsole.log(11)
Copy code
9. The caching proxy
It can provide temporary storage for some expensive operation results , In the next calculation , If the parameters passed in are the same as before , You can directly return the previously stored operation results
9.1 Calculate the product
var mult = function(){
var a = 1;
for(var i=0, l = arguments.length; i < l; i++) {
a = a * arguments[i];
}
return a;
}
var proxyMult = (function(){
var cache = {};
return function(){
var args = Array.prototype.join.call(arguments, ',');
if (args in cache) {
return cache[args];
}
return cache[args] = mult.apply(this, arguments);
}
})();
proxyMult(1,2,3,4)
proxyMult(1,2,3,4) // Directly returns the previously cached calculation results
Copy code
10. Creating proxies dynamically with higher-order functions
By passing in higher-order functions in a more flexible way , You can create cache proxies for various calculation methods . Now these calculations are passed as parameters into a factory dedicated to creating cache agents , We can multiply 、 Add 、 Subtraction, etc. create cache proxy
// Calculate the product
var mult = function(){
var a = 1;
for(var i=0, l = arguments.length; i<l;i++) {
a = a * arguments[i];
}
return a;
}
// Calculate the sum
var plus = function(){
var a = 0;
for(var i=0, l = arguments.length; i<l;i++) {
a = a + arguments[i];
}
return a;
}
// Create a factory for caching agents
var createProxyFactory = function(fn) {
var chache = {}
return function(){
var args = Array.prototype.join.call(arguments, ',');
if (args in cache) {
return cache[args];
}
return cache[args] = fn.apply(this, arguments);
}
}
var proxyMult = createProxyFactory(mult),
proxyPlus = createProxyFactory(plus);
alert(proxyMult(1,2,3,4))
alert(proxyMult(1,2,3,4))
alert(proxyPlus(1,2,3,4))
alert(proxyPlus(1,2,3,4))
Copy code
11. Other agency models
- Firewall proxy : Controls access to network resources
- Remote agent : Provide local representation of an object in different address spaces
- Protection agency : Used when the object should have different access rights
- Intelligent reference agent : Instead of a simple pointer , It performs some additional operations when accessing objects , For example, calculate the number of times an object is referenced
- Copy agent on write : It is usually used to copy a large object . The write time replication agent delays the replication process , When the object is actually modified , Just copy it . The copy on write agent is a variant of the virtual agent ,DLL( Dynamic link library in operating system ) It is a typical application scenario .
stay JavaScript The most commonly used in development are virtual agents and cache agents .
版权声明
本文为[Xiao Guo is in Shenzhen]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/09/20210909122358706d.html