【プレーンデザインパターン】 7. プロキシパターン&Pythonサンプル(構造パターンの始まり)

専門的なプレゼンテーション:

このオブジェクトへのアクセスを制御するために、他のオブジェクトにプロキシを提供します。このとき、アクセスオブジェクトは対象オブジェクトを直接参照できない、または適切ではないため、プロキシオブジェクトがアクセスオブジェクトと対象オブジェクトとの間の仲介役となる。

人気の紹介: 

場合によっては、ユーザー (クライアント) がオブジェクトに直接アクセスできないことがあります。これは、次の理由が考えられます。

       1.一部のクライアント/コンシューマによってこのオブジェクトが変更されないように保護する必要があります。

       2. このオブジェクトの一部の機能を拡張または削除したいが、このオブジェクトを直接変更できない/不便

       3. オブジェクトへの直接アクセスのコストが高すぎるため、オブジェクトに代わってアクセスし、ユーザーに提供するには中間オブジェクトが必要です。

クライアントが使用する仲介者 (エージェント) を提供し、仲介者はオブジェクトに直接アクセスしてクライアントにサービスを提供します。

 例: 研究開発部門は、DB データをクエリするためのインターフェースをデータ開発部門に提供する必要があります。データ開発部門にはクエリ (選択) 権限のみが必要で、その他の権限は必要ありません。このとき、研究開発部門は通常、次のように記述しますhttpプロトコルに基づくインターフェースで、インターフェース内で権限が制限されている場合、このインターフェースをデータベースアクセスエージェントと呼ぶことができます(ミドルウェアも使用できます)。

プロキシ モードには 3 つの役割があります。

  • 抽象的なテーマ
  • 本当の主題
  • 演技

プロキシ モードの欠点:

         1. 訪問者と訪問者の間にレイヤーが追加されるため、アクセス速度がある程度低下します

         2. システムの複雑さの増加。

次のコードは、上記の例を (クラスの形式で) 解決します。

コード:

# 代理模式

import abc, six


# step-1: 定义抽象主题
@six.add_metaclass(abc.ABCMeta)
class AbstractDBAccessSubject:
    @abc.abstractmethod
    def select(self, sql): pass

    @abc.abstractmethod
    def delete(self, sql): pass

    @abc.abstractmethod
    def insert(self, sql): pass

    @abc.abstractmethod
    def update(self, sql): pass


# step-2: 定义具体主题
class DBAccesSubject(AbstractDBAccessSubject):
    def select(self, sql):
        return self.execute_sql(sql, 'select')

    def delete(self, sql):
        return self.execute_sql(sql, 'delete')

    def insert(self, sql):
        return self.execute_sql(sql, 'insert')

    def update(self, sql):
        return self.execute_sql(sql, 'update')

    def execute_sql(self, sql, op):
        return 'real_data', sql, op


# step-3: 定义代理(继承具体主题)
class DBAccesProxy(DBAccesSubject):
    def __init__(self, user, passwd):
        account_check = {
            'user1': {
                'passwd': 123, 'permission': ['select']
            }
        }
        self.user = ''
        self.permission = []
        self.logged = False
        u = account_check.get(user, {})
        if u.get('passwd') and u.get('passwd') == passwd:
            self.user = user
            self.permission = u.get('permission')
            self.logged = True
            return
        print('Invalid user and passwd!')

    def select(self, sql):
        if 'select' not in self.permission:
            print('Insufficient authority!')
            return
        return super(DBAccesProxy, self).select(sql)

    def delete(self, sql):
        if 'delete' not in self.permission:
            print('Insufficient authority!')
            return
        return super(DBAccesProxy, self).delete(sql)

    def insert(self, sql):
        if 'insert' not in self.permission:
            print('Insufficient authority!')
            return
        return super(DBAccesProxy, self).insert(sql)

    def update(self, sql):
        if 'update' not in self.permission:
            print('Insufficient authority!')
            return
        return super(DBAccesProxy, self).update(sql)


if __name__ == '__main__':
    db_access_proxy = DBAccesProxy('xxx', 123)  # Invalid user and passwd!
    # if not db_access_proxy.logged:
    #     exit()
    db_access_proxy = DBAccesProxy('user1', 123)
    s = db_access_proxy.select('select * from x')
    print(s)  # ('real_data', 'select * from x', 'select')
    db_access_proxy.update('update x set a=1')  # Insufficient authority!

説明: コードから、プロキシ クラスは DB アクセスを提供することに基づいて、ID 認証と権限制御機能も提供し、非侵襲的な拡張を実現していることがわかります。

コードによれば、プロキシ モードの 2 つの欠点もわかります。

  1. 実トピックと代理トピックは 1 対 1 に対応しており、実トピックを追加すると代理トピックも増加します。
  2. エージェントの設計 以前は実際のトピックが事前に存在する必要があり、あまり柔軟性がありませんでした。(動的プロキシ モードを使用すると、上記の問題を解決できます)

 

注: abc および 6 つのライブラリの基本的な使用法については、「 シンプルなファクトリ パターンと Python の例」の記事の最後にある概要を参照してください 。:)

メッセージを残してください~

 

 

参考記事:

http://c.biancheng.net/view/1354.html

おすすめ

転載: blog.csdn.net/sc_lilei/article/details/103365858