小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

結(jié)構(gòu)型模式之代理模式

 新進(jìn)小設(shè)計(jì) 2021-07-13

在有些情況下,一個(gè)客戶不能或者不想直接訪問另一個(gè)對(duì)象,這時(shí)需要找一個(gè)中介幫忙完成某項(xiàng)任務(wù),這個(gè)中介就是代理對(duì)象。

定義與特點(diǎn)

由于某些原因需要給某對(duì)象提供一個(gè)代理以控制對(duì)該對(duì)象的訪問。這時(shí),訪問對(duì)象不適合或者不能直接引用目標(biāo)對(duì)象,代理對(duì)象作為訪問對(duì)象和目標(biāo)對(duì)象之間的中介。

主要優(yōu)點(diǎn)有:

  • 代理模式在客戶端與目標(biāo)對(duì)象之間起到一個(gè)中介作用和保護(hù)目標(biāo)對(duì)象的作用

  • 代理對(duì)象可以擴(kuò)展目標(biāo)對(duì)象的功能。

  • 代理模式能將客戶端與目標(biāo)對(duì)象分離,在一定程度上降低了系統(tǒng)的耦合度。

主要缺點(diǎn)有:

  • 在客戶端和目標(biāo)對(duì)象之間增加一個(gè)代理對(duì)象,會(huì)造成請(qǐng)求處理速度變慢

  • 增加了系統(tǒng)的復(fù)雜度。

結(jié)構(gòu)與實(shí)現(xiàn)

代理模式的結(jié)構(gòu)比較簡單,主要是通過定義一個(gè)繼承抽象主題的代理來包含真實(shí)主題,從而實(shí)現(xiàn)對(duì)真實(shí)主題的訪問。

模式的結(jié)構(gòu)

代理模式的主要角色如下:

  • 抽象主題(Subject)類:通過接口或抽象類(推薦使用接口)聲明真實(shí)主題和代理對(duì)象實(shí)現(xiàn)的業(yè)務(wù)方法

  • 真實(shí)主題(Real Subject)類:實(shí)現(xiàn)了抽象主題中的具體業(yè)務(wù),是代理對(duì)象所代表的真實(shí)對(duì)象,是最終要引用的對(duì)象。

  • 代理(Proxy)類:提供了與真實(shí)主題相同的接口,其內(nèi)部含有對(duì)真實(shí)主題的引用,它可以訪問、控制或擴(kuò)展真實(shí)主題的功能

其結(jié)構(gòu)圖如圖所示:

模式的實(shí)現(xiàn)

代理模式的實(shí)現(xiàn)代碼如下:

//訪問類
class Program
{
    static void Main(string[] args)
    {
        //代理模式        
        Proxy proxy=new Proxy();
        proxy.Request();       
        Console.ReadKey();
    }
}

//抽象主題
public interface ISubject
{
    void Request();
}

//真實(shí)主題
public class RealSubject :ISubject
{
    public void Request()
    {
        Console.WriteLine("訪問真實(shí)主題方法...");
    }
}

//代理
public class Proxy : ISubject
{
    private RealSubject realSubject;
    public void Request()
    {
        if (realSubject==null)
        {
            realSubject=new RealSubject();
        }
        PreRequest();
        realSubject.Request();
        PostRequest();
    }
    public void PreRequest()
    {
        Console.WriteLine("訪問真實(shí)主題之前的預(yù)處理。");
    }
    public void PostRequest()
    {
        Console.WriteLine("訪問真實(shí)主題之后的后續(xù)處理。");
    }
}

程序運(yùn)行的結(jié)果如下:

訪問真實(shí)主題之前的預(yù)處理。
訪問真實(shí)主題方法...
訪問真實(shí)主題之后的后續(xù)處理。

應(yīng)用場(chǎng)景

前面分析了代理模式的結(jié)構(gòu)與特點(diǎn),現(xiàn)在來分析以下的應(yīng)用場(chǎng)景:

  • 遠(yuǎn)程代理(Remote Proxy):這種方式通常是為了隱藏目標(biāo)對(duì)象存在于不同地址空間的事實(shí),方便客戶端訪問。
    例如,用戶訪問網(wǎng)盤的虛擬硬盤時(shí)實(shí)際訪問的是網(wǎng)盤空間。

  • 虛擬代理(Virtual Proxy):這種方式通常用于要?jiǎng)?chuàng)建的目標(biāo)對(duì)象開銷很大時(shí)。
    例如,下載一幅很大的圖像需要很長時(shí)間,這時(shí)可以先用小比例的虛擬代理替換真實(shí)的對(duì)象,消除用戶對(duì)服務(wù)器慢的感覺。

  • 保護(hù)代理(Protection Proxy):這種方式通常用于控制不同種類客戶對(duì)真實(shí)對(duì)象的訪問權(quán)限。

  • 智能指引(Smart Reference):主要用于調(diào)用目標(biāo)對(duì)象時(shí),代理附加一些額外的處理功能。

智能指引的典型用途包括:

  • 增加計(jì)算真實(shí)對(duì)象的引用次數(shù)的功能,這樣當(dāng)該對(duì)象沒有被引用時(shí),就可以自動(dòng)釋放它;

  • 當(dāng)?shù)谝淮我靡粋€(gè)持久對(duì)象時(shí),將它裝入內(nèi)存。

  • 在訪問一個(gè)實(shí)際對(duì)象前,檢查是否已經(jīng)鎖定了它,以確保其他對(duì)象不能改變它。

擴(kuò)展:動(dòng)態(tài)代理模式

在前面介紹的代理模式中,代理類中包含了對(duì)真實(shí)主題的引用,這種方式存在兩個(gè)缺點(diǎn):

  • 真實(shí)主題與代理主題一一對(duì)應(yīng),增加真實(shí)主題也要增加代理。

  • 設(shè)計(jì)代理以前真實(shí)主題必須事先存在,不太靈活。

采用動(dòng)態(tài)代理模式可以解決以上問題(如 SpringAOP),C#中可以使用RealProxy實(shí)現(xiàn)動(dòng)態(tài)代理,有兩種方法:
第一種:只使用RealProxy,不能代理帶out參數(shù)的方法(可能是我沒找到),代碼如下:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("***\r\n Begin program - logging with decorator\r\n");
        IRepository<Customer> customerRepository =RepositoryFactory.Create<Customer>();
        var customer = new Customer()
        {
            Id = 1,
            Name = "Customer 1",
            Address = "Address 1"
        };
        customerRepository.Add(customer);
        customerRepository.Update(customer);
        customerRepository.Delete(customer);
        Console.WriteLine("\r\nEnd program - logging with decorator\r\n***");
        Console.ReadLine();
    }
}
//客戶類
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
}

//存儲(chǔ)庫接口
public interface IRepository<T>
{
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    IEnumerable<T> GetAll();
    T GetById(int id);
}

//真實(shí)儲(chǔ)存庫
public class Repository<T> : IRepository<T>
{
    public void Add(T entity)
    {
        Console.WriteLine("Adding {0}", entity);
    }
    public void Delete(T entity)
    {
        Console.WriteLine("Deleting {0}", entity);
    }
    public void Update(T entity)
    {
        Console.WriteLine("Updating {0}", entity);
    }
    public IEnumerable<T> GetAll()
    {
        Console.WriteLine("Getting entities");
        return null;
    }
    public T GetById(int id)
    {
        Console.WriteLine("Getting entity {0}", id);
        return default(T);
    }
} 

//動(dòng)態(tài)代理
class DynamicProxy<T> : RealProxy
{
    private readonly T _decorated;
    public DynamicProxy(T decorated) : base(typeof(T))
    {
        _decorated = decorated;
    }
    private void Log(string msg, object arg = null)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine(msg, arg);
        Console.ResetColor();
    }
    public override IMessage Invoke(IMessage msg)
    {
        var methodCall = msg as IMethodCallMessage;
        var methodInfo = methodCall.MethodBase as MethodInfo;
        Log("In Dynamic Proxy - Before executing '{0}'",methodCall.MethodName);
        try
        {
            var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
            Log("In Dynamic Proxy - After executing '{0}' ",methodCall.MethodName);
            return new ReturnMessage(result, null, 0,methodCall.LogicalCallContext, methodCall);
        }
        catch (Exception e)
        {
            Log(string.Format("In Dynamic Proxy- Exception {0} executing '{1}'", e),methodCall.MethodName);
            return new ReturnMessage(e, methodCall);
        }
    }
}

//存?zhèn)}庫過程,自動(dòng)執(zhí)行代理
public class RepositoryFactory
{
    public static IRepository<T> Create<T>()
    {
        var repository = new Repository<T>();
        var dynamicProxy = new DynamicProxy<IRepository<T>>(repository);
        return dynamicProxy.GetTransparentProxy() as IRepository<T>;
    }
}

第二種:使用RealProxy、MarshalByRefObject,可以代理帶out參數(shù)的方法,代碼如下:

//訪問類
public class Program
{
    static void Main(string[] args)
    {
        //動(dòng)態(tài)代理模式        
        Proxy<ISubject> proxy = new Proxy<ISubject>(new RealSubject());
        ISubject subject = (ISubject)proxy.GetTransparentProxy();
        int arg = 0;
        subject.Request(out arg); 
        Console.WriteLine(arg);
        Console.ReadKey();
    }
}
//代理類
public class Proxy<T> : RealProxy where T: class
{    
    MarshalByRefObject myMarshalByRefObject;
    public Proxy(MarshalByRefObject realT) : base(typeof(T))
    {        
        myMarshalByRefObject = realT;
    }
    public override IMessage Invoke(IMessage myMessage)
    {        
        IMethodCallMessage myCallMessage = (IMethodCallMessage)myMessage;
        Console.WriteLine("動(dòng)態(tài)代理方法中:執(zhí)行前");
        IMethodReturnMessage myIMethodReturnMessage = RemotingServices.ExecuteMessage(myMarshalByRefObject, myCallMessage);
        Console.WriteLine("動(dòng)態(tài)代理方法中:執(zhí)行后");
        return myIMethodReturnMessage;
    }
}

//抽象主題
public interface ISubject
{
    void Request(out int arg);
}

//真實(shí)主題
public class RealSubject : MarshalByRefObject,ISubject
{
    public void Request(out int arg)
    {
        arg = 1;
        Console.WriteLine("訪問真實(shí)主題方法...");       
    }
}

參考資料    

C#中動(dòng)態(tài)代理與泛型函數(shù)——CSDN
面向方面的編程-使用 RealProxy 類進(jìn)行面向方面的編程——MSDN

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多