意圖
代理模式主要是為了控制對象的通路,意圖隻要有以下三種:
1、代理模式主要是為另一個對象提供代理,以控制對另一個對象的通路。
2、通過代理間接支援分布式、受控以及智能通路,
3、添加一個包裝器或者委托以保護真正的元件不受過度複雜性的影響。
代理的種類
設計一個代理:當用戶端第一次請求代理時,就執行個體化真實的對象,并将引發的請求轉發給這個真實的對象。然後,所有之後的請求都直接轉發到封裝的真實對象。
主要有四種代理:
1、虛拟代理。當建立對象的代價非常高時,使用這種代理作為該對象的一個“替代品”。真實的對象隻有在用戶端第一次通路或者請求的時候建立(比如說圖檔加載)。
2、遠端代理。此為遠端對象的本地代表(在不同的位址空空間運作的遠端對象)。本地代表是指可以由本地方法調用的對象,其行為會轉發到遠端對象中。比如說RPC中的stub,skeleton,就是提供了遠端代理的功能。
3、保護代理。這種代理主要控制對敏感對象的通路。代理對象檢查調用方是否具有各種所需的通路權限。
4、智能代理。主要用在通路對象時插入其他操作。
- 計算實際對象的引用次數,當沒有其他對象引用該對象時,自動釋放該對象(智能指針)
- 當第一次引用持久對象時,将其加載到記憶體中
- 在通路真實對象之前檢查它是否被鎖定,以確定沒有其他對象可以更改它。
遠端代理
能夠調用本地對象,然後将每個請求轉發到遠端對象上。此時,需要一些輔助對象,來協助我們做這些事情。這些輔助對象使客戶就像在調用本地對象的方法一樣。
客戶調用客戶輔助對象上的方法,方法客戶輔助對象就是真正的服務。客戶輔助對象再負責為我們轉發這些請求。
在服務端,服務輔助對象從客戶輔助對象中接受請求(通過socket連接配接),将調用的資訊解包,然後調用真正服務對象上的真正方法。
服務輔助對象可以從服務中得到傳回值,将它打包,然後運回客戶輔助對象,客戶輔助對象對資訊解包,最後将傳回值交給客戶對象,
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TU65UMjpXT6VEVNdXVzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcukzMyEDOwETM0EzMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
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)
}