编程知识 cdmana.com

Design pattern -- agent pattern

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

Scroll to Top