こんにちは兄弟姉妹、長い間更新されていませんでした。今日は、元のオブジェクトを変更せずにプロキシ オブジェクトを介して元のオブジェクトへのアクセスを制御することを目的とした、非常に単純なデザイン モードであるプロキシ モードについて簡単に紹介します。プロキシモードは、特定の状況に応じて、リモートプロキシ、仮想プロキシ、保護プロキシなどに分けることもできます。これについては以下で紹介します。
目次
1.エージェントモードの基本紹介
1.1 基本
C++ プロキシ パターンは、他のオブジェクトへのアクセスを制御するプロキシを提供することを主な目的とする構造設計パターンです。プロキシ オブジェクトは、元のオブジェクトのラッパーとして機能し、要求を元のオブジェクトに転送し、要求の転送前または転送後にいくつかの追加操作を実行できます。
プロキシ モードは通常、次の状況で使用されます。
- リモート プロキシ: 異なるアドレス空間にある 2 つのオブジェクト間の通信に使用され、リモート オブジェクトに要求を送信します。
-
Virtual Proxy : 遅延読み込み、つまり必要なときにリソースを読み込むために使用されます。
-
Protection Proxy : オブジェクトへのアクセスを制御するために使用されます。たとえば、特定のユーザーのみがオブジェクトにアクセスできます。
-
キャッシング プロキシ: オブジェクトのアクセス結果をキャッシュして、計算量の多い操作の繰り返し実行を回避するために使用されます。
C++ でプロキシ パターンを実装すると、抽象クラスとインターフェイスを使用してプロキシと元のオブジェクト間の通信プロトコルを定義し、具象クラスを使用してそれらを実装できます。プロキシ オブジェクトはリクエストを元のオブジェクトに転送し、リクエストの転送前または転送後にいくつかの追加操作を実行できます。
1.2 コード例
以下は、単純な C++ プロキシ モードのサンプル コードです。
#include <iostream>
using namespace std;
// 定义抽象类 Subject,代表原始对象和代理对象共同的接口
class Subject {
public:
virtual void request() = 0;
};
// 定义具体类 RealSubject,实现原始对象的功能
class RealSubject : public Subject {
public:
void request() override {
cout << "RealSubject: Handling request." << endl;
}
};
// 定义代理类 Proxy,实现代理对象的功能
class Proxy : public Subject {
private:
RealSubject* real_subject_;
void check_access() const {
cout << "Proxy: Checking access prior to handling request." << endl;
}
public:
Proxy(RealSubject* real_subject) : real_subject_(real_subject) {}
void request() override {
check_access();
real_subject_->request();
}
};
int main() {
RealSubject* real_subject = new RealSubject;
Proxy* proxy = new Proxy(real_subject);
proxy->request();
delete proxy;
delete real_subject;
return 0;
}
この例では、抽象クラス Subject が元のオブジェクトとプロキシ オブジェクトの共通のインターフェイス request() を定義し、具象クラス RealSubject が元のオブジェクトの機能を実現し、プロキシ クラス Proxy がプロキシ オブジェクトの機能を実現し、追加操作 check_access() を実行します。main() 関数では、RealSubject オブジェクトと Proxy オブジェクトが作成され、その Proxy オブジェクトを介して request() メソッドが呼び出されます。
クラス図は次のとおりです。
2. リモート プロキシ
C++ リモート プロキシは、クライアントがプロキシ オブジェクトを介して間接的にリモート サービスまたはオブジェクトにアクセスできるようにする設計パターンです。このパターンは、 RPC (リモート プロシージャ コール)や分散システムなどのネットワーク プログラミングでよく使用されます。
// 假设这是远程服务端对象的头文件
class RemoteService {
public:
virtual void foo() = 0;
};
// 代理类,用于访问远程服务端对象
class RemoteServiceProxy : public RemoteService {
public:
RemoteServiceProxy(const std::string& host, int port) : m_host(host), m_port(port) {}
void foo() override {
// 连接远程服务端
connect();
// 向远程服务端发送请求
sendRequest("foo");
// 等待远程服务端响应
std::string response = receiveResponse();
// 关闭连接
disconnect();
// 处理响应
processResponse(response);
}
private:
std::string m_host;
int m_port;
int m_socketFd; // 保存套接字描述符,用于连接远程服务端
void connect() {
// 连接远程服务端代码
}
void sendRequest(const std::string& request) {
// 向远程服务端发送请求代码
}
std::string receiveResponse() {
// 从远程服务端接收响应代码
}
void disconnect() {
// 关闭连接代码
}
void processResponse(const std::string& response) {
// 处理响应代码
}
};
// 客户端代码
int main() {
RemoteServiceProxy proxy("127.0.0.1", 8080);
proxy.foo(); // 通过代理对象间接访问远程服务端对象的foo()方法
return 0;
}
上記のコードで、RemoteService は、リモート サーバー オブジェクトのインターフェイスを定義する抽象基本クラスです。RemoteServiceProxy は、ソケット記述子を介してリモート サーバーに接続し、クライアントの要求をリモート サーバーに転送するプロキシ クラスです。クライアントは、リモート サーバーの特定の実装の詳細を知らなくても、プロキシ オブジェクトを介してリモート サーバーのメソッドにアクセスするだけで済みます。
クラス図は次のとおりです。
3. 仮想プロキシ
C++ 仮想プロキシ (仮想プロキシ) パターンは、実際のオブジェクトの代わりにプロキシ オブジェクトを作成できる構造設計パターンです。プロキシ オブジェクトは、実際のオブジェクトへのアクセスを制御し、必要な場合にのみ実際のオブジェクトを作成またはロードできます。
コード例:
#include <iostream>
using namespace std;
// 定义一个抽象类Subject
class Subject {
public:
virtual void request() = 0;
};
// 定义一个真实的Subject类RealSubject
class RealSubject : public Subject {
public:
void request() {
cout << "真实的请求" << endl;
}
};
// 定义一个代理类Proxy
class Proxy : public Subject {
private:
RealSubject *realSubject;
public:
void request() {
if (realSubject == nullptr) {
realSubject = new RealSubject();
}
cout << "代理请求" << endl;
realSubject->request();
}
};
// 客户端代码
int main() {
Proxy proxy;
proxy.request();
return 0;
}
上記の例では、抽象クラス Subject と具象クラス RealSubject を定義しました。どちらも request() メソッドを実装しています。次に、request() メソッドも実装するプロキシ クラス Proxy を定義しますが、実際のサブジェクトが作成されているかどうかを最初に確認し、作成されていない場合は作成します。次に、プロキシ クラスは、プロキシ要求を示すメッセージを出力します。最後に、実際のサブジェクトの request() メソッドを呼び出します。
クライアント コードでは、プロキシ オブジェクトをインスタンス化し、request() メソッドを呼び出します。プロキシ パターンを使用したため、プロキシ オブジェクトの request() メソッドを呼び出すと、最初に実際のオブジェクトが作成され (作成されていない場合)、次にプロキシ リクエストが出力され、最後に実際のオブジェクトの request() メソッドが呼び出されます。物体。
このパターンの利点の 1 つは、実際に必要になるまで実際のオブジェクトの作成を遅らせることです。これにより、特に実際のオブジェクトの作成に費用がかかる場合に、リソースを節約できます。
クラス図:
4. 保護プロキシ
C++ のプロテクティブ プロキシは、オブジェクトへのアクセスを制御することを目的とした構造設計パターンです。プロキシ オブジェクトを使用して元のオブジェクトへのアクセスを制御します。プロキシ オブジェクトは、元のオブジェクトへのアクセスを制限または制御することにより、追加のセキュリティと保護を提供します。
#include <iostream>
#include <string>
#include <memory>
class Image {
public:
Image(std::string name) : name_(name) {}
virtual void Display() = 0;
virtual ~Image() {}
protected:
std::string name_;
};
class RealImage : public Image {
public:
RealImage(std::string name) : Image(name) {
LoadFromDisk();
}
void Display() override {
std::cout << "Displaying " << name_ << std::endl;
}
private:
void LoadFromDisk() {
std::cout << "Loading " << name_ << " from disk" << std::endl;
}
};
class ImageProxy : public Image {
public:
ImageProxy(std::string name) : Image(name) {}
void Display() override {
if (real_image_ == nullptr) {
real_image_ = std::make_unique<RealImage>(name_);
}
real_image_->Display();
}
private:
std::unique_ptr<RealImage> real_image_;
};
int main() {
// Create a real image object
auto real_image = std::make_unique<RealImage>("image1.jpg");
// Display the real image
real_image->Display();
// Create an image proxy object
auto image_proxy = std::make_unique<ImageProxy>("image2.jpg");
// Display the image proxy
image_proxy->Display();
// The real image is only loaded once, even though it is displayed twice
return 0;
}
上記のサンプル コードでは、Image が抽象基本クラスで、RealImage と ImageProxy が具象クラスです。RealImage は、ディスクから画像を読み込んで表示できる実画像オブジェクトです。ImageProxy は、実画像オブジェクトにアクセスできるプロキシ オブジェクトであり、実画像オブジェクトの読み込みと表示を担当します。ImageProxy オブジェクトの Display() メソッドを呼び出すと、まず実際の画像オブジェクトが読み込まれているかどうかがチェックされます。読み込まれていない場合は、RealImage オブジェクトを使用して画像を読み込みます。この方法により、実画像オブジェクトへの頻繁なアクセスを減らすことができ、それによってプログラムの効率が向上します。
クラス図:
5.キャッシュプロキシ
キャッシング プロキシ モードの基本的な考え方は次のとおりです。関数またはメソッドが呼び出されるたびに計算が繰り返されるのを避けるために、結果をキャッシュし、次回必要になったときにキャッシュされた結果を計算せずに直接返すことができます。
#include <iostream>
#include <unordered_map>
using namespace std;
// 定义一个全局的缓存代理类
class FactorialCacheProxy {
public:
int getFactorial(int n) {
if (cache_.find(n) != cache_.end()) {
// 如果结果已经被缓存,直接返回缓存的结果
cout << "Get result from cache: " << n << endl;
return cache_[n];
} else {
// 如果结果没有被缓存,进行计算并缓存结果
cout << "Calculate result: " << n << endl;
int result = calculateFactorial(n);
cache_[n] = result;
return result;
}
}
private:
// 计算阶乘的实际函数
int calculateFactorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
// 使用一个 unordered_map 来作为缓存
unordered_map<int, int> cache_;
};
int main() {
FactorialCacheProxy cacheProxy;
for (int i = 5; i <= 7; i++) {
int result = cacheProxy.getFactorial(i);
cout << "Factorial of " << i << " is " << result << endl;
}
for (int i = 5; i <= 7; i++) {
int result = cacheProxy.getFactorial(i);
cout << "Factorial of " << i << " is " << result << endl;
}
return 0;
}
結果を計算し、結果をキャッシュします。後で同じメソッドが再度呼び出されると、結果はそれ以上計算せずにキャッシュから直接フェッチされるため、プログラムのパフォーマンスが向上します。
6. まとめ
プロキシモードのプロキシされるオブジェクトには、いくつかの特殊性が必要です. オブジェクトのロードが困難であるか、計算が困難である. プロキシをバッファとして設計する必要があり、プロキシは必要に応じて実オブジェクトを起こします. 上記の特性を満たすものはすべてプロキシモードを使用でき、デザインモードは自然であり、プログラムの実行におけるペインポイントを解決するために生まれました。
ブロガーは、みんなに幸せな週末を願っています!