代理模式------讀書筆記

意圖

代理模式主要是爲了控制對象的訪問,意圖只要有以下三種:
1、代理模式主要是爲另一個對象提供代理,以控制對另一個對象的訪問。
2、通過代理間接支持分佈式、受控以及智能訪問,
3、添加一個包裝器或者委託以保護真正的組件不受過度複雜性的影響。

代理的種類

設計一個代理:當客戶端第一次請求代理時,就實例化真實的對象,並將引發的請求轉發給這個真實的對象。然後,所有之後的請求都直接轉發到封裝的真實對象。

主要有四種代理:
1、虛擬代理。當創建對象的代價非常高時,使用這種代理作爲該對象的一個“替代品”。真實的對象只有在客戶端第一次訪問或者請求的時候創建(比如說圖片加載)。
2、遠程代理。此爲遠程對象的本地代表(在不同的地址空空間運行的遠程對象)。本地代表是指可以由本地方法調用的對象,其行爲會轉發到遠程對象中。比如說RPC中的stub,skeleton,就是提供了遠程代理的功能。
3、保護代理。這種代理主要控制對敏感對象的訪問。代理對象檢查調用方是否具有各種所需的訪問權限。
4、智能代理。主要用在訪問對象時插入其他操作。

  • 計算實際對象的引用次數,當沒有其他對象引用該對象時,自動釋放該對象(智能指針)
  • 當第一次引用持久對象時,將其加載到內存中
  • 在訪問真實對象之前檢查它是否被鎖定,以確保沒有其他對象可以更改它。

遠程代理

能夠調用本地對象,然後將每個請求轉發到遠程對象上。此時,需要一些輔助對象,來協助我們做這些事情。這些輔助對象使客戶就像在調用本地對象的方法一樣。

客戶調用客戶輔助對象上的方法,方法客戶輔助對象就是真正的服務。客戶輔助對象再負責爲我們轉發這些請求。

在服務端,服務輔助對象從客戶輔助對象中接受請求(通過socket連接),將調用的信息解包,然後調用真正服務對象上的真正方法。

服務輔助對象可以從服務中得到返回值,將它打包,然後運回客戶輔助對象,客戶輔助對象對信息解包,最後將返回值交給客戶對象,

在這裏插入圖片描述

java RMI

RMI提供了客戶輔助對象和服務輔助對象,爲客戶輔助對象創建和服務對象相同的方法。RMI的好處在於你不必晴子寫任何網絡或I/O代碼。客戶程序調用遠程方法就和在運行在客戶自己的本地JVM上對對象進行正常方法調用一樣。
RMI將客戶輔助對象稱爲stub(樁),把服務輔助對象稱爲skeleton(骨架)。

類圖

在這裏插入圖片描述

java動態代理

類圖

在這裏插入圖片描述

我們使用java的動態代理來實現保護代理。因爲java已經爲你創建了proxy類,所以你需要有什麼辦法來告訴Proxy類你要做什麼。我們不能像以前一樣把代碼放到proxy中,因爲proxy不是我們直接實現的,我們把它放到InvocationHandle中,這個類的工作是相應代理的任何調用,你可以把InvocationHandler想成是代理收到方法調用後,請求做實際工作的對象。

我們爲什麼要使用動態代理呢?比如說我們實現一個打分系統,該系統有個人年齡性別等信息,也有別人給自己的評分信息。,我們自己不可以改變自己的HotOrNot評分,也不可以改變其他人的個人信息,因此,我們需要創建兩個代理,一個訪問你自己的PersonBean對象,另一個訪問另一人的PersonBean對象。這樣代理就可以控制在每一種情況下允許哪一種請求。
創建這種代理,必須使用java中的動態代理。

代碼

個人信息接口類

 interface PersonBean{
        fun getName() : String?
        fun getGender() : String?
        fun getInterests() : String?
        fun getHotOrNotRating() : Int?
    
        fun setName(name: String)
        fun setGender(gender : String)
        fun setInterests(interest : String)
        fun setHotOrNotRating(hotRating : Int)
    
    }

個人信息實現類

class PersonBeanImpl : PersonBean{
    var nameStr : String? = null
    var genderStr : String? = null
    var interestStr : String? = null
    var hotRatingInt : Int? = 0
    var ratingCount = 0

    override fun getName(): String? {
        return nameStr
    }

    override fun getGender(): String? {
        return genderStr
    }

    override fun getInterests(): String? {
        return interestStr
    }

    override fun getHotOrNotRating(): Int? {
        if (ratingCount == 0){
            return 0
        }
        return hotRatingInt?.div(ratingCount)
    }

    override fun setName(name: String) {
        nameStr = name
    }

    override fun setGender(gender: String) {
        genderStr = gender
    }

    override fun setInterests(interest: String) {
        interestStr = interest
    }

    override fun setHotOrNotRating(hotRating: Int) {
        hotRatingInt?.plus(hotRating)
        ratingCount++
    }

}

真正實現控制訪問的handler

自己的信息

  import java.lang.reflect.InvocationHandler
    import java.lang.reflect.Method
    
    /**
     * 自己只能修改年齡性別等信息,而不能修改自己的評分等信息。
     */
    
    class OwnerInvocationHandler(val personBean: PersonBeanImpl) : InvocationHandler{
        override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
            if (method!!.name.startsWith("get")){
                return method.invoke(personBean, args!![0])
            }else if (method.name == "setHotOrNotRating"){
                throw IllegalAccessException()
            }else if (method.name.startsWith("set")){
                method.invoke(personBean, args!![0])
            }
            return "null"
        }
    
    }

別人的信息

import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method

/**
 * 別人只能更改其他的評分,而不能修改別人的性別年齡等信息
 */
class NonOwnerInvocationHandler (val personBean: PersonBeanImpl): InvocationHandler{
    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
        if (method!!.name.startsWith("get")){
            throw IllegalAccessException()
        }else if (method.name == "setHotOrNotRating"){
            return method.invoke(personBean, args!![0])
        }else if (method.name.startsWith("set")){
            throw IllegalAccessException()
        }
        return "null"
    }

}

測試類

import java.lang.reflect.Proxy

fun main(args : Array<String>){
    val person  = PersonBeanImpl()
    val personProxy  = Proxy.newProxyInstance(person.javaClass.classLoader,person.javaClass.interfaces, OwnerInvocationHandler(person)) as PersonBean
    personProxy.setGender("3")
    print(personProxy)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章