// 服务连接器的具体实现。该类的方法可以向腾讯视频请求信息。请求速度取决于 // 用户和腾讯视频的互联网连接情况。如果同时发送大量请求,即使所请求的信息 // 一模一样,程序的速度依然会减慢。 class ThirdPartyTVClass implements ThirdPartyTVLib is method listVideos() is // 向腾讯视频发送一个 API 请求。
method getVideoInfo(id) is // 获取某个视频的元数据。
method downloadVideo(id) is // 从腾讯视频下载一个视频文件。
// 为了节省网络带宽,我们可以将请求结果缓存下来并保存一段时间。但你可能无 // 法直接将这些代码放入服务类中。比如该类可能是第三方程序库的一部分或其签 // 名是`final(最终)`。因此我们会在一个实现了服务类接口的新代理类中放入 // 缓存代码。当代理类接收到真实请求后,才会将其委派给服务对象。 class CachedTVClass implements ThirdPartyTVLib is private field service: ThirdPartyTVLib private field listCache, videoCache field needReset
namespaceRefactoringGuru.DesignPatterns.Proxy.Conceptual { // 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. publicinterfaceISubject { voidRequest(); } // 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. classRealSubject : ISubject { publicvoidRequest() { Console.WriteLine("RealSubject: Handling Request."); } } // The Proxy has an interface identical to the RealSubject. classProxy : ISubject { private RealSubject _realSubject; publicProxy(RealSubject realSubject) { this._realSubject = realSubject; } // 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. publicvoidRequest() { if (this.CheckAccess()) { this._realSubject.Request();
this.LogAccess(); } } publicboolCheckAccess() { // Some real checks should go here. Console.WriteLine("Proxy: Checking access prior to firing a real request.");
returntrue; } publicvoidLogAccess() { Console.WriteLine("Proxy: Logging the time of request."); } } publicclassClient { // 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. publicvoidClientCode(ISubject subject) { // ... subject.Request(); // ... } } classProgram { staticvoidMain(string[] args) { Client client = new Client(); Console.WriteLine("Client: Executing the client code with a real subject:"); RealSubject realSubject = new RealSubject(); client.ClientCode(realSubject);
Console.WriteLine();
Console.WriteLine("Client: Executing the same client code with a proxy:"); Proxy proxy = new Proxy(realSubject); client.ClientCode(proxy); } } }
Output.txt: 执行结果
1 2 3 4 5 6 7
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.
在 C++ 中使用模式
复杂度: ★★☆
流行度: ★☆☆
使用示例: 尽管代理模式在绝大多数 C++ 程序中并不常见, 但它在一些特殊情况下仍然非常方便。 当你希望在无需修改客户代码的前提下于已有类的对象上增加额外行为时, 该模式是无可替代的。
#include<iostream> /** * 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. */ classSubject { public: virtualvoidRequest()const= 0; }; /** * 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. */ classRealSubject : public Subject { public: voidRequest()constoverride{ std::cout << "RealSubject: Handling request.\n"; } }; /** * The Proxy has an interface identical to the RealSubject. */ classProxy : public Subject { /** * @var RealSubject */ private: RealSubject *real_subject_;
boolCheckAccess()const{ // Some real checks should go here. std::cout << "Proxy: Checking access prior to firing a real request.\n"; returntrue; } voidLogAccess()const{ std::cout << "Proxy: Logging the time of request.\n"; }
/** * The Proxy maintains a reference to an object of the RealSubject class. It * can be either lazy-loaded or passed to the Proxy by the client. */ public: Proxy(RealSubject *real_subject) : real_subject_(newRealSubject(*real_subject)) { }
~Proxy() { delete real_subject_; } /** * 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. */ voidRequest()constoverride{ if (this->CheckAccess()) { this->real_subject_->Request(); this->LogAccess(); } } }; /** * 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. */ voidClientCode(const Subject &subject){ // ... subject.Request(); // ... }
intmain(){ std::cout << "Client: Executing the client code with a real subject:\n"; RealSubject *real_subject = new RealSubject; ClientCode(*real_subject); std::cout << "\n"; std::cout << "Client: Executing the same client code with a proxy:\n"; Proxy *proxy = newProxy(real_subject); ClientCode(*proxy);
delete real_subject; delete proxy; return0; }
Output.txt: 执行结果
1 2 3 4 5 6 7
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.
Connecting to http://www.youtube.com... Connected! Downloading populars... Done!
------------------------------- Most popular videos on YouTube (imagine fancy HTML) ID: sadgahasgdas / Title: Catzzzz.avi ID: asdfas3ffasd / Title: Dancing video.mpq ID: 3sdfgsd1j333 / Title: Programing lesson#1.avi ID: mkafksangasj / Title: Dog play with ball.mp4 ID: dlsdk5jfslaf / Title: Barcelona vs RealM.mov -------------------------------
Connecting to http://www.youtube.com/catzzzzzzzzz... Connected! Downloading video... Done!
------------------------------- Video page (imagine fancy HTML) ID: catzzzzzzzzz Title: Some video title Video: Random video. -------------------------------
Connecting to http://www.youtube.com... Connected! Downloading populars... Done!
------------------------------- Most popular videos on YouTube (imagine fancy HTML) ID: sadgahasgdas / Title: Catzzzz.avi ID: asdfas3ffasd / Title: Dancing video.mpq ID: 3sdfgsd1j333 / Title: Programing lesson#1.avi ID: mkafksangasj / Title: Dog play with ball.mp4 ID: dlsdk5jfslaf / Title: Barcelona vs RealM.mov -------------------------------
Connecting to http://www.youtube.com/dancesvideoo... Connected! Downloading video... Done!
------------------------------- Video page (imagine fancy HTML) ID: dancesvideoo Title: Some video title Video: Random video. -------------------------------
Connecting to http://www.youtube.com/catzzzzzzzzz... Connected! Downloading video... Done!
------------------------------- Video page (imagine fancy HTML) ID: catzzzzzzzzz Title: Some video title Video: Random video. -------------------------------
Connecting to http://www.youtube.com/someothervid... Connected! Downloading video... Done!
------------------------------- Video page (imagine fancy HTML) ID: someothervid Title: Some video title Video: Random video. -------------------------------
Time elapsed: 9354ms Connecting to http://www.youtube.com... Connected! Downloading populars... Done!
------------------------------- Most popular videos on YouTube (imagine fancy HTML) ID: sadgahasgdas / Title: Catzzzz.avi ID: asdfas3ffasd / Title: Dancing video.mpq ID: 3sdfgsd1j333 / Title: Programing lesson#1.avi ID: mkafksangasj / Title: Dog play with ball.mp4 ID: dlsdk5jfslaf / Title: Barcelona vs RealM.mov -------------------------------
Connecting to http://www.youtube.com/catzzzzzzzzz... Connected! Downloading video... Done!
------------------------------- Video page (imagine fancy HTML) ID: catzzzzzzzzz Title: Some video title Video: Random video. -------------------------------
Retrieved list from cache.
------------------------------- Most popular videos on YouTube (imagine fancy HTML) ID: sadgahasgdas / Title: Catzzzz.avi ID: asdfas3ffasd / Title: Dancing video.mpq ID: 3sdfgsd1j333 / Title: Programing lesson#1.avi ID: mkafksangasj / Title: Dog play with ball.mp4 ID: dlsdk5jfslaf / Title: Barcelona vs RealM.mov -------------------------------
Connecting to http://www.youtube.com/dancesvideoo... Connected! Downloading video... Done!
------------------------------- Video page (imagine fancy HTML) ID: dancesvideoo Title: Some video title Video: Random video. -------------------------------
Retrieved video 'catzzzzzzzzz' from cache.
------------------------------- Video page (imagine fancy HTML) ID: catzzzzzzzzz Title: Some video title Video: Random video. -------------------------------
Connecting to http://www.youtube.com/someothervid... Connected! Downloading video... Done!
------------------------------- Video page (imagine fancy HTML) ID: someothervid Title: Some video title Video: Random video. -------------------------------
Time elapsed: 5875ms Time saved by caching proxy: 3479ms
/** * 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. */ interfaceSubject { publicfunctionrequest(): void; }
/** * 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. */ classRealSubjectimplementsSubject { publicfunctionrequest(): void { echo"RealSubject: Handling request.\n"; } }
/** * The Proxy has an interface identical to the RealSubject. */ classProxyimplementsSubject { /** * @var RealSubject */ private$realSubject;
/** * The Proxy maintains a reference to an object of the RealSubject class. It * can be either lazy-loaded or passed to the Proxy by the client. */ publicfunction__construct(RealSubject $realSubject) { $this->realSubject = $realSubject; }
/** * 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. */ publicfunctionrequest(): void { if ($this->checkAccess()) { $this->realSubject->request(); $this->logAccess(); } }
privatefunctioncheckAccess(): bool { // Some real checks should go here. echo"Proxy: Checking access prior to firing a real request.\n";
returntrue; }
privatefunctionlogAccess(): void { echo"Proxy: Logging the time of request.\n"; } }
/** * 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. */ functionclientCode(Subject $subject) { // ...
$subject->request();
// ... }
echo"Client: Executing the client code with a real subject:\n"; $realSubject = newRealSubject(); clientCode($realSubject);
echo"\n";
echo"Client: Executing the same client code with a proxy:\n"; $proxy = newProxy($realSubject); clientCode($proxy);
Output.txt: 执行结果
1 2 3 4 5 6 7
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.
/** * The Subject interface describes the interface of a real object. * * The truth is that many real apps may not have this interface clearly defined. * If you're in that boat, your best bet would be to extend the Proxy from one * of your existing application classes. If that's awkward, then extracting a * proper interface should be your first step. */ interfaceDownloader { publicfunctiondownload(string$url): string; }
/** * The Real Subject does the real job, albeit not in the most efficient way. * When a client tries to download the same file for the second time, our * downloader does just that, instead of fetching the result from cache. */ classSimpleDownloaderimplementsDownloader { publicfunctiondownload(string$url): string { echo"Downloading a file from the Internet.\n"; $result = file_get_contents($url); echo"Downloaded bytes: " . strlen($result) . "\n";
return$result; } }
/** * The Proxy class is our attempt to make the download more efficient. It wraps * the real downloader object and delegates it the first download calls. The * result is then cached, making subsequent calls return an existing file * instead of downloading it again. * * Note that the Proxy MUST implement the same interface as the Real Subject. */ classCachingDownloaderimplementsDownloader { /** * @var SimpleDownloader */ private$downloader;
publicfunctiondownload(string$url): string { if (!isset($this->cache[$url])) { echo"CacheProxy MISS. "; $result = $this->downloader->download($url); $this->cache[$url] = $result; } else { echo"CacheProxy HIT. Retrieving result from cache.\n"; } return$this->cache[$url]; } }
/** * The client code may issue several similar download requests. In this case, * the caching proxy saves time and traffic by serving results from cache. * * The client is unaware that it works with a proxy because it works with * downloaders via the abstract interface. */ functionclientCode(Downloader $subject) { // ...
echo"Executing client code with real subject:\n"; $realSubject = newSimpleDownloader(); clientCode($realSubject);
echo"\n";
echo"Executing the same client code with a proxy:\n"; $proxy = newCachingDownloader($realSubject); clientCode($proxy);
Output.txt: 执行结果
1 2 3 4 5 6 7 8 9 10
Executing client code with real subject: Downloading a file from the Internet. Downloaded bytes: 1270 Downloading a file from the Internet. Downloaded bytes: 1270
Executing the same client code with a proxy: CacheProxy MISS. Downloading a file from the Internet. Downloaded bytes: 1270 CacheProxy HIT. Retrieving result from cache.
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
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.
# 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. classSubject # @abstract defrequest raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
# 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. classRealSubject < Subject defrequest puts 'RealSubject: Handling request.' end end
# The Proxy has an interface identical to the RealSubject. classProxy < Subject # @param [RealSubject] real_subject definitialize(real_subject) @real_subject = real_subject end
# 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. defrequest returnunless check_access
@real_subject.request log_access end
# @return [Boolean] defcheck_access puts 'Proxy: Checking access prior to firing a real request.' true end
deflog_access print 'Proxy: Logging the time of request.' end end
# 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. defclient_code(subject) # ...
subject.request
# ... end
puts 'Client: Executing the client code with a real subject:' real_subject = RealSubject.new client_code(real_subject)
puts "\n"
puts 'Client: Executing the same client code with a proxy:' proxy = Proxy.new(real_subject) client_code(proxy)
output.txt: 执行结果
1 2 3 4 5 6 7
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.
在 Swift 中使用模式
复杂度: ★★☆
流行度: ★☆☆
使用示例: 尽管代理模式在绝大多数 Swift 程序中并不常见, 但它在一些特殊情况下仍然非常方便。 当你希望在无需修改客户代码的前提下于已有类的对象上增加额外行为时, 该模式是无可替代的。
/// 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. protocolSubject {
funcrequest() }
/// 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. classRealSubject: Subject {
/// The Proxy has an interface identical to the RealSubject. classProxy: Subject {
privatevar realSubject: RealSubject
/// The Proxy maintains a reference to an object of the RealSubject class. /// It can be either lazy-loaded or passed to the Proxy by the client. init(_realSubject: RealSubject) { self.realSubject = realSubject }
/// 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. funcrequest() {
if (checkAccess()) { realSubject.request() logAccess() } }
privatefunccheckAccess() -> Bool {
/// Some real checks should go here.
print("Proxy: Checking access prior to firing a real request.")
returntrue }
privatefunclogAccess() { print("Proxy: Logging the time of request.") } }
/// 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. classClient { // ... staticfuncclientCode(subject: Subject) { // ... print(subject.request()) // ... } // ... }
/// Let's see how it all works together. classProxyConceptual: XCTestCase {
functest() { print("Client: Executing the client code with a real subject:") let realSubject =RealSubject() Client.clientCode(subject: realSubject)
print("\nClient: Executing the same client code with a proxy:") let proxy =Proxy(realSubject) Client.clientCode(subject: proxy) } }
/// Proxy Design Pattern /// /// Intent: Provide a surrogate or placeholder for another object to control /// access to the original object or to add other responsibilities. /// /// Example: There are countless ways proxies can be used: caching, logging, /// access control, delayed initialization, etc.
functestProxyRealWorld() {
print("Client: Loading a profile WITHOUT proxy") loadBasicProfile(with: Keychain()) loadProfileWithBankAccount(with: Keychain())
print("\nClient: Let's load a profile WITH proxy") loadBasicProfile(with: ProfileProxy()) loadProfileWithBankAccount(with: ProfileProxy()) }
service.loadProfile(with: [.basic, .bankAccount], success: { profile in print("Client: Basic profile with a bank account is loaded") }) { error in print("Client: Cannot load a profile with a bank account") print("Client: Error: "+ error.localizedSummary) } } }
iflet error = checkAccess(for: fields) { failure(error) } else { /// Note: /// At this point, the `success` and `failure` closures can be /// passed directly to the original service (as it is now) or /// expanded here to handle a result (for example, to cache).
for item in fields { switch item { case .basic: let info = loadBasicProfile() profile.firstName = info[Profile.Keys.firstName.raw] profile.lastName = info[Profile.Keys.lastName.raw] profile.email = info[Profile.Keys.email.raw] case .bankAccount: profile.bankAccount = loadBankAccount() } }
success(profile) }
privatefuncloadBasicProfile() -> [String : String] { /// Gets these fields from a secure storage. return [Profile.Keys.firstName.raw : "Vasya", Profile.Keys.lastName.raw : "Pupkin", Profile.Keys.email.raw : "vasya.pupkin@gmail.com"] }
privatefuncloadBankAccount() -> BankAccount { /// Gets these fields from a secure storage. returnBankAccount(id: 12345, amount: 999) } }
classBiometricsService {
enumAccess { case authorized case denied }
staticfunccheckAccess() -> Access { /// The service uses Face ID, Touch ID or a plain old password to /// determine whether the current user is an owner of the device.
/// Let's assume that in our example a user forgot a password :) return .denied } }
structProfile {
enumKeys: String { case firstName case lastName case email }
var firstName: String? var lastName: String? var email: String?
var bankAccount: BankAccount? }
structBankAccount {
var id: Int var amount: Double }
enumProfileError: LocalizedError {
case accessDenied
var errorDescription: String? { switchself { case .accessDenied: return"Access is denied. Please enter a valid password" } } }
extensionRawRepresentable {
var raw: Self.RawValue { return rawValue } }
extensionLocalizedError {
var localizedSummary: String { return errorDescription ??"" } }
Output.txt: 执行结果
1 2 3 4 5 6 7 8
Client: Loading a profile WITHOUT proxy Client: Basic profile is loaded Client: Basic profile with a bank account is loaded
Client: Let's load a profile WITH proxy Client: Basic profile is loaded Client: Cannot load a profile with a bank account Client: Error: Access is denied. Please enter a valid password
/** * 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. */ interfaceSubject { request(): void; }
/** * 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. */ classRealSubjectimplementsSubject { publicrequest(): void { console.log('RealSubject: Handling request.'); } }
/** * The Proxy has an interface identical to the RealSubject. */ classProxyimplementsSubject { privaterealSubject: RealSubject;
/** * The Proxy maintains a reference to an object of the RealSubject class. It * can be either lazy-loaded or passed to the Proxy by the client. */ constructor(realSubject: RealSubject) { this.realSubject = realSubject; }
/** * 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. */ publicrequest(): void { if (this.checkAccess()) { this.realSubject.request(); this.logAccess(); } }
privatecheckAccess(): boolean { // Some real checks should go here. console.log('Proxy: Checking access prior to firing a real request.');
returntrue; }
privatelogAccess(): void { console.log('Proxy: Logging the time of request.'); } }
/** * 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. */ functionclientCode(subject: Subject) { // ...
subject.request();
// ... }
console.log('Client: Executing the client code with a real subject:'); const realSubject = newRealSubject(); clientCode(realSubject);
console.log('');
console.log('Client: Executing the same client code with a proxy:'); const proxy = newProxy(realSubject); clientCode(proxy);
Output.txt: 执行结果
1 2 3 4 5 6 7
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 这样的 Web 服务器可充当应用程序服务器的代理:
提供了对应用程序服务器的受控访问权限。
可限制速度。
可缓存请求。
server.go: 主体
1 2 3 4 5
package main
type server interface { handleRequest(string, string) (int, string) }