Design pattern notes - agent pattern
Introduction to agent mode
The proxy mode is usually an intermediary system between the requester and the provider. The requester is the party who sends the request, and the provider is the party who provides the corresponding resources according to the request
The proxy server in the Web is an example. The client sends a network request to the proxy server, connects to the proxy server, evaluates the request, sends the encapsulated request to the corresponding remote server, and sends the response to the client after receiving the response. In this process, the proxy server acts as an intermediary and encapsulates the request, Privacy protection is ideal for running in a distributed architecture
The proxy mode acts as the class of the actual object interface, and the object types are diverse. For large objects in network connection, memory and files, the proxy encapsulates the wrapper or agent of the actual service object. It can provide additional functions for the wrapped object without changing the object code. Its main purpose is to provide a proxy or placeholder for the actual object, So as to control the actual access of objects, it has many adaptation scenarios
- For a complex system, agents can represent it in a simple way to encapsulate its internal complexity
- It can protect the actual object and improve the security of the actual object. In many cases, the client is not allowed to directly access the actual object
- Provides local interfaces for remote objects on different servers
- Provides a lightweight handle to a remote object that consumes a lot of memory
PS:
When the production company wants to find actors to make movies, they usually communicate directly with the Agent rather than with the actors. The Agent will determine whether the actors are free according to the actors' schedule, so as to give the negotiation results. The production company (client) does not directly find the actors (actual objects), but directly communicate with their agents (Agent agents)
class Actor(object): def __init__(self): self.isBusy = False def occupied(self): self.isBusy = True print(type(self).__name__, "is occupied with Current movie") def available(self): self.isBusy = False print(type(self).__name__, "is free for the movie") def getStatus(self): return self.isBusy class Agent(object): def __init__(self): self.principal = None def work(self): self.actor = Actor() if self.actor.getStatus(): self.actor.occupied() else: self.actor.available() if __name__ == "__main__": r = Agent() r.work()
- The proxy mode provides a proxy for other objects to realize the access control of the original object
- Used as a layer or interface to support distributed access
- It can increase agents and protect real components from accidental effects
UML class diagram
UML is composed of three participants: Proxy, real object RealSubject and topic Subject. The UML composition diagram is as follows:
Proxy: maintain a reference, allow the proxy to access the actual object through this reference, and provide the same interface as the Subject, so that the proxy can replace the real Subject. It is also responsible for creating and deleting the real Subject
Subject: defines the public interface of RealSubject and proxy, and the formal subject. Proxy can be used anywhere RealSubject is used
Real subject: it defines the real object represented by the Proxy
Throughout the UML diagram, you can see:
**Agent: * * class that controls access to RealSubject class, handles client requests, and is responsible for creating and deleting RealSubject
Topic / real topic: defines the public interface between real topics and agents, and real topics provide real implementation of functions
**Client: * * it accesses the Proxy class that completes the work. The Proxy is responsible for the access and control of RealSubject and responds to the request of the client
Four types of agent models
Virtual agent
If an object instantiation takes up a lot of memory, it can be represented by a placeholder first. You can't really access the object until you really request it. That is, in a Web site, if the loading of a large image requires a lot of resources, it will be represented by a placeholder before clicking it until you really click the image, It will be displayed, that is, to create the actual object
Remote agent
Provide a local representation for the actual objects located on the remote server or in the address space at different locations. For example, you want the application to establish a monitoring system, and the application involves multiple Web servers, database servers, celery task servers, cache servers, etc. If you want to monitor the CPU, memory and disk utilization of these services, you need to establish an object to monitor the context in which the application is running. At the same time, you can also execute remote commands to obtain parameter values.
Protection agent
To control the access to sensitive instance objects, the proxy will first verify the request legally when the client sends the request, so as to prevent illegal requests from causing the collapse of remote object instances. The agent will check whether the caller has the access rights required to forward the request
intelligent agent
When accessing objects, pull in other operations. For example, suppose there is a core component in the system that stores state information in one place. Usually, such components need to be called by multiple different services to complete their tasks, and may lead to the problem of sharing resources. Unlike letting the service call the core component directly, the intelligent agent is built-in and checks whether the actual object is locked before accessing to ensure that no other object changes it
example
Taking a person who goes to the store to buy water as an example, wechat now supports wechat payment, code scanning and payment. Wechat can be understood as acting as an agent, and the bank behind the deduction is the one who really performs the deduction. Wechat only helps maintain this interface and encapsulates the specific operations of the bank. Here, it is assumed that the client is You, You, During initialization, the agent will be called to instantiate the real object through make_pay to pay, and through__ del__ To give the payment results
For wechat wechat, both he and Bank have realized a do of payment_ Pay method. In this process, the Bank performs real deduction operation through the account information sent by wechat, except do_ In addition to the pay method, there are__ hasEnoughMenoy to check whether the balance is sufficient, setAccount to set the account information__ Reduce balance to deduct money through__ checkAccount to verify whether the user and user password are correct, and wechat calls do of Bank_ Pay to realize deduction operation
Python implementation
# -*- coding=utf-8 -*- from abc import ABCMeta, abstractmethod BankAccountData: dict = { "acc1":["10001", 50], "acc2":["10002", 100] } class Payment(metaclass=ABCMeta): @abstractmethod def do_pay(self, pay: int) -> bool: pass class Bank(Payment): account: str password: str def __init__(self): self.account = None self.password = None def setAccount(self): self.account = input("Please input the account:") self.password = input("Please input the password:") def __checkAccount(self) -> bool: if self.account in BankAccountData: if self.password == BankAccountData[self.account][0]: return True return False def __reduceBalance(self, money: int) -> bool: if self.__hasEnoughMeony(money): BankAccountData[self.account][1] -= money return True return False def __hasEnoughMeony(self, money: int) -> bool: if self.__checkAccount(): if money <= BankAccountData[self.account][1]: return True return False print("Account or Password that you input is error!") return False def do_pay(self, pay: int) -> bool: return self.__reduceBalance(pay) class WetChat(Payment): def __init__(self): self.bank = Bank() def do_pay(self, pay: int) -> bool: self.bank.setAccount() return self.bank.do_pay(pay) class You(object): def __init__(self): print("Let me buy the water!") self.wetchat = WetChat() self.isPurchased = None def make_pay_water(self): self.isPurchased = self.wetchat.do_pay(2) def __del__(self): if self.isPurchased: print("Pay successfully!") else: print("Pay failed!") if __name__ == "__main__": you = You() you.make_pay_water()
Let me buy the water! Please input the account:acc1 Please input the password:10001 Pay successfully!
C + + implementation
#include<iostream> #include<map> #include<string> using namespace std; map<string, pair<string, int>> bank_account_data = {{"acc1",pair<string, int>("10001", 50)}, {"acc2",pair<string, int>("10002", 100)}}; class Payment{ public: virtual bool do_pay(int money) = 0; }; class Bank:public Payment{ public: Bank(){ account = ""; password = ""; } public: void setAccount(){ cout<<"Please input the account:"; cin>>account; cout<<"Please input the password:"; cin>>password; } bool do_pay(int money) override{ return __reduceBalance(money); } private: bool __checkAccount(){ if(bank_account_data.find(account) != bank_account_data.end()){ auto res = bank_account_data[account]; if(password == res.first){ return true; } } return false; } bool __hasEnoughMoney(int money){ if(__checkAccount()){ if(money <= bank_account_data[account].second) return true; return false; } cout<<"Account or Password that you input is error!"<<endl; return false; } bool __reduceBalance(int money){ if(__hasEnoughMoney(money)){ bank_account_data[account].second -= money; return true; } return false; } private: string account; string password; }; class WetChat: public Payment{ public: WetChat(){ bank = new Bank(); } public: bool do_pay(int money) override{ bank->setAccount(); return bank->do_pay(money); } private: Bank *bank; }; class You{ public: You(){ cout<<"Let me but the water!"<<endl; wetchat = WetChat(); isPurchased = false; } ~You(){ if(isPurchased) cout<<"Pay successfully!"<<endl; else cout<<"Pay failed!"<<endl; } public: void make_pay_water(){ isPurchased = wetchat.do_pay(2); } private: WetChat wetchat; bool isPurchased; }; int main(int argc, char *argv[]){ You you = You(); you.make_pay_water(); }
Let me but the water! Please input the account:acc1 Please input the password:10001 Pay successfully!
Advantages of agent mode
- Agents can improve program performance by caching bulky objects or frequently accessed objects
- Provide access privileges to real topics, so this mode will accept delegation only if appropriate permissions are provided
- Remote code also facilitates interaction with remote servers that can be used as network and database connections
Facade mode and agent mode
Both of them are structural design patterns. The similarity is that they are real objects with an agent / facade in front of them, but there are differences in intention between the two patterns
proxy pattern | Facade mode |
---|---|
Placeholders are provided for other objects to control access to the original object | Provides an interface to a large subsystem of a class |
It has the same interface as its target object and saves a reference to the object | The communication and dependency between subsystems are minimized |
Acts as a mediator between the client and the encapsulated object | Provides a single simple interface |