Design Pattern - Proxy Pattern代理模式

認識Proxy Pattern

Proxy Pattern(代理模式):

是常見的設計模式之一,一般在中大系統要引用第三方控件時,會使用Proxy Pattern,主要用來隔離呼叫端及目的端,降低呼叫端及目的端的相依性,提升程式的可變性及延展性。

一般我們需要讀取外部檔案且Json序列化或反序列化,下列程式碼,直接相依Newtonsoft.Json的JsonConvert.DeserializeObject,當需要更換Text.Json或是其他套件時,可能就需要改動專案很多地方。

namespace ConsoleApp1
{
   class Program
   {
       static void Main(string[] args)
       {
           try
           {
               var path = $"{AppDomain.CurrentDomain.BaseDirectory}/Myfile.txt";
               using (var r = new StreamReader(path))
               {
                   //相依Newtonsoft.Json
                   foreach (var item in JsonConvert.DeserializeObject<IEnumerable<MyClass>>(r.ReadToEnd()))
                   {
                       Console.WriteLine(item.Name);
                       Console.WriteLine(item.Age);
                       Console.WriteLine("=============");
                   }
               }
           }
           catch (Exception ex)
           {
               Console.WriteLine(ex);
           }
           Console.ReadLine();
       }
   }
   public class MyClass
   {
       public string Name { get; set; }
       public string Age { get; set; }
   }
}

這時會新建一層中介層(Proxy Pattern)來降低呼叫端及目的端的相依性。

JsonParseProxy.cs:

namespace JsonParseProxy
{
   public class JsonParseProxy
   {
       private string fileName;
       public JsonParseProxy(string fileName)
       {
           this.fileName = fileName;
       }
       public IEnumerable<T> Load<T>()
       {
           try
           {
               using (var r = new StreamReader(fileName))
               {
                   return JsonConvert.DeserializeObject<IEnumerable<T>>(r.ReadToEnd());
               }
           }
           catch (IOException ex)
           {
               throw new JsonParseProxySettingException($"load file setting from {fileName}  fail", ex);
           }
           catch (JsonReaderException ex)
           {
               throw new JsonParseProxySettinggParseException($"parse file setting from {fileName} fail", ex);
           }
       }
   }
   [Serializable]
   public class JsonParseProxySettingException : Exception
   {
       public JsonParseProxySettingException(string message) : base(message)
       {
       }
       public JsonParseProxySettingException(string message, Exception inner) : base(message, inner)
       {
       }
   }
   [Serializable]
   public class JsonParseProxySettinggParseException : Exception
   {
       public JsonParseProxySettinggParseException(string message) : base(message)
       {
       }
       public JsonParseProxySettinggParseException(string message, Exception inner) : base(message, inner)
       {
       }
   }
}

Program.cs:

namespace JsonParseProxy
{
   class Program
   {
       static void Main(string[] args)
       {
           try
           {
               var r = new JsonParseProxy($"{AppDomain.CurrentDomain.BaseDirectory}/Myfile.txt");
               foreach (var item in r.Load<MyClass>())
               {
                   Console.WriteLine(item.Name);
                   Console.WriteLine(item.Age);
                   Console.WriteLine("=============");
               }
           }
           catch (Exception ex)
           {
               Console.WriteLine(ex);
           }
           Console.ReadLine();
       }
   }
   public class MyClass
   {
       public string Name { get; set; }
       public string Age { get; set; }
   }
}

上述程式碼我們多切了一層中介層,讓呼叫端相依JsonParseProxy.cs,當需要更換實作或套件時,只需要異動JsonParseProxy.cs,並且也制定了Domain Exception,則提供了更清楚 的例外辨識度,我們把IOException 及 JsonReaderException 封裝後拋出,因為呼叫者不需要得知你的內部行為。