// The interface of a remote service. interfaceThirdPartyYouTubeLib is method listVideos() method getVideoInfo(id) method downloadVideo(id)
// The concrete implementation of a service connector. Methods // of this class can request information from YouTube. The speed // of the request depends on a user's internet connection as // well as YouTube's. The application will slow down if a lot of // requests are fired at the same time, even if they all request // the same information. classThirdPartyYouTubeClassimplementsThirdPartyYouTubeLib is method listVideos() is // Send an API request to YouTube.
method getVideoInfo(id) is // Get metadata about some video.
method downloadVideo(id) is // Download a video file from YouTube.
// To save some bandwidth, we can cache request results and keep // them for some time. But it may be impossible to put such code // directly into the service class. For example, it could have // been provided as part of a third party library and/or defined // as `final`. That's why we put the caching code into a new // proxy class which implements the same interface as the // service class. It delegates to the service object only when // the real requests have to be sent. classCachedYouTubeClassimplementsThirdPartyYouTubeLib is private field service: ThirdPartyYouTubeLib private field listCache, videoCache field needReset
constructor CachedYouTubeClass(service: ThirdPartyYouTubeLib) is this.service = service
method downloadVideo(id) is if(!downloadExists(id) || needReset) service.downloadVideo(id)
// The GUI class, which used to work directly with a service // object, stays unchanged as long as it works with the service // object through an interface. We can safely pass a proxy // object instead of a real service object since they both // implement the same interface. classYouTubeManager is protected field service: ThirdPartyYouTubeLib
constructor YouTubeManager(service: ThirdPartyYouTubeLib) is this.service = service
method renderVideoPage(id)is info= service.getVideoInfo(id) // Render the video page.
method renderListPanel()is list= service.listVideos() // Render the list of video thumbnails.
method reactOnUserInput() is renderVideoPage() renderListPanel()
// The application can configure proxies on the fly. classApplication is method init()is aYouTubeService=newThirdPartyYouTubeClass() aYouTubeProxy = newCachedYouTubeClass(aYouTubeService) manager = newYouTubeManager(aYouTubeProxy) manager.reactOnUserInput()
classSubject(ABC): """ The Subject interface declares common operations for both RealSubject and the Proxy. As long as the client works with RealSubject using this interface, you'll be able to pass it a proxy instead of a real subject. """
@abstractmethod defrequest(self) -> None: pass
classRealSubject(Subject): """ The RealSubject contains some core business logic. Usually, RealSubjects are capable of doing some useful work which may also be very slow or sensitive - e.g. correcting input data. A Proxy can solve these issues without any changes to the RealSubject's code. """
defrequest(self) -> None: """ The most common applications of the Proxy pattern are lazy loading, caching, controlling the access, logging, etc. A Proxy can perform one of these things and then, depending on the result, pass the execution to the same method in a linked RealSubject object. """
if self.check_access(): self._real_subject.request() self.log_access()
defcheck_access(self) -> bool: print("Proxy: Checking access prior to firing a real request.") returnTrue
deflog_access(self) -> None: print("Proxy: Logging the time of request.", end="")
defclient_code(subject: Subject) -> None: """ The client code is supposed to work with all objects (both subjects and proxies) via the Subject interface in order to support both real subjects and proxies. In real life, however, clients mostly work with their real subjects directly. In this case, to implement the pattern more easily, you can extend your proxy from the real subject's class. """
# ...
subject.request()
# ...
if __name__ == "__main__": print("Client: Executing the client code with a real subject:") real_subject = RealSubject() client_code(real_subject)
print("")
print("Client: Executing the same client code with a proxy:") proxy = Proxy(real_subject) client_code(proxy)
Output.txt:执行结果
1 2 3 4 5 6 7 8
Client: Executing the client code with a real subject: RealSubject: Handling request.
Client: Executing the same client code with a proxy: Proxy: Checking access prior to firing a real request. RealSubject: Handling request. Proxy: Logging the time of request.
/// NGINX server is a proxy to an application server. pubstructNginxServer { application: Application, max_allowed_requests: u32, rate_limiter: HashMap<String, u32>, }