天天看點

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

意圖

代理模式主要是為了控制對象的通路,意圖隻要有以下三種:

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)
}
           

繼續閱讀