外观模式

外观模式定义: 外观模式:为子系统中的一组接口提供一个统一的入口。

图3 外观模式结构图

 

由图3可知,外观模式包含如下两个角色:

(1) Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。

(2) SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。

子系统类,其典型代码如下:

class SubSystemA  
{  
    public void MethodA()  
    {  
        //业务实现代码  
    }  
}  

class SubSystemB  
{  
    public void MethodB()  
    {  
        //业务实现代码  
     }  
}  

class SubSystemC  
{  
    public void MethodC()  
    {  
        //业务实现代码  
    }  
}

在引入外观类之后,与子系统业务类之间的交互统一由外观类来完成,在外观类中通常存在如下代码:

class Facade  
{  
    private SubSystemA obj1 = new SubSystemA();  
    private SubSystemB obj2 = new SubSystemB();  
    private SubSystemC obj3 = new SubSystemC();  

    public void Method()  
    {  
        obj1.MethodA();  
        obj2.MethodB();  
        obj3.MethodC();  
    }  
}

引入外观类后,客户端代码变得非常简单,典型代码如下:

class Program  
{  
    static void Main(string[] args)  
    {  
        Facade facade = new Facade();  
        facade.Method();  
    }  
}

1.实例说明

某软件公司欲开发一个可应用于多个软件的文件加密模块,该模块可以对文件中的数据进行加密并将加密之后的数据存储在一个新文件中,具体的流程包括三个部分,分别是读取源文件、加密、保存加密之后的文件,其中,读取文件和保存文件使用流来实现,加密操作通过求模运算实现。这三个操作相对独立,为了实现代码的独立重用,让设计更符合单一职责原则,这三个操作的业务代码封装在三个不同的类中。

  1. 实例类图
 

图4 文件加密模块结构图

在图4中,EncryptFacade充当外观类,FileReader、CipherMachine和FileWriter充当子系统类。

(1) FileReader:文件读取类,充当子系统类。

class FileReader  
    {  
        public string Read(string fileNameSrc)   
        {  
       Console.Write("读取文件,获取明文:");  
            FileStream fs = null;  
            StringBuilder sb = new StringBuilder();  
       try  
            {  
                fs = new FileStream(fileNameSrc, FileMode.Open);  
                int data;  
               while((data = fs.ReadByte())!= -1)   
                {  
            sb = sb.Append((char)data);  
               }  
               fs.Close();  
               Console.WriteLine(sb.ToString());  
       }  
       catch(FileNotFoundException e)   
            {  
           Console.WriteLine("文件不存在!");  
       }  
       catch(IOException e)   
            {  
           Console.WriteLine("文件操作错误!");  
       }  
       return sb.ToString();  
        }  
    }  

(2) CipherMachine:数据加密类,充当子系统类。

 

 class CipherMachine  
    {  
       public string Encrypt(string plainText)   
       {  
       Console.Write("数据加密,将明文转换为密文:");  
       string es = "";  
            char[] chars = plainText.ToCharArray();  
       foreach(char ch in chars)   
            {  
                string c = (ch % 7).ToString();  
           es += c;  
       }  
            Console.WriteLine(es);  
       return es;  
    }  
    }  

(3) FileWriter:文件保存类,充当子系统类。

class FileWriter  
    {  
        public void Write(string encryptStr,string fileNameDes)   
        {  
       Console.WriteLine("保存密文,写入文件。");  
            FileStream fs = null;  
       try  
            {  
               fs = new FileStream(fileNameDes, FileMode.Create);  
                byte[] str = Encoding.Default.GetBytes(encryptStr);  
                fs.Write(str,0,str.Length);  
                fs.Flush();  
               fs.Close();  
       }      
       catch(FileNotFoundException e)   
            {  
        Console.WriteLine("文件不存在!");  
       }  
       catch(IOException e)   
            {  
                Console.WriteLine(e.Message);  
           Console.WriteLine("文件操作错误!");  
       }          
        }  
    }  

(4) EncryptFacade:加密外观类,充当外观类。

 

class EncryptFacade  
    {  
        //维持对其他对象的引用  
         private FileReader reader;  
        private CipherMachine cipher;  
        private FileWriter writer;  

        public EncryptFacade()  
        {  
            reader = new FileReader();  
            cipher = new CipherMachine();  
            writer = new FileWriter();  
        }  

        //调用其他对象的业务方法  
         public void FileEncrypt(string fileNameSrc, string fileNameDes)  
        {  
            string plainStr = reader.Read(fileNameSrc);  
            string encryptStr = cipher.Encrypt(plainStr);  
            writer.Write(encryptStr, fileNameDes);  
        }  
    }  

(5) Program:客户端测试类

 

class Program  
    {  
        static void Main(string[] args)  
        {  
            EncryptFacade ef = new EncryptFacade();  
            ef.FileEncrypt("src.txt", "des.txt");  
            Console.Read();  
        }  
    }  

1.抽象外观类

 在标准的外观模式结构图中,如果需要增加、删除或更换与外观类交互的子系统类,必须修改外观类或客户端的源代码,这将违背开闭原则,因此可以通过引入抽象外观类来对系统进行改进,在一定程度上可以解决该问题。

如果在应用实例“文件加密模块”中需要更换一个加密类,不再使用原有的基于求模运算的加密类CipherMachine,而改为基于移位运算的新加密类NewCipherMachine

如何在不修改客户端代码的前提下使用新的外观类呢?解决方法之一是:引入一个抽象外观类,客户端针对抽象外观类编程,而在运行时再确定具体外观类,引入抽象外观类之后的文件加密模块结构图如图5所示:

 

 

图5 引入抽象外观类之后的文件加密模块结构图

在图5中,客户类Client针对抽象外观类AbstractEncryptFacade进行编程,AbstractEncryptFacade代码如下:
abstract class AbstractEncryptFacade  
    {  
        public abstract void FileEncrypt(string fileNameSrc, string fileNameDes);  
    }  

新增具体加密外观类:

class NewEncryptFacade : AbstractEncryptFacade  
    {  
        private FileReader reader;  
        private NewCipherMachine cipher;  
        private FileWriter writer;  

        public NewEncryptFacade()  
        {  
            reader = new FileReader();  
            cipher = new NewCipherMachine();  
            writer = new FileWriter();  
        }  

        public override void FileEncrypt(string fileNameSrc, string fileNameDes)  
        {  
            string plainStr = reader.Read(fileNameSrc);  
            string encryptStr = cipher.Encrypt(plainStr);  
            writer.Write(encryptStr, fileNameDes);  
        }  
    }  

App.config:

<?xml version="1.0" encoding="utf-8" ?>  
<configuration>  
  <appSettings>  
    <add key="facade" value="NewEncryptFacade"/>  
  </appSettings>  
</configuration>

客户端测试代码修改如下:

 

 class Program  
    {  
        static void Main(string[] args)  
        {  
            AbstractEncryptFacade ef; //针对抽象外观类编程  
            //读取配置文件  
            string facadeString = ConfigurationManager.AppSettings["facade"];  
            //反射生成对象  
            ef = (AbstractEncryptFacade)Assembly.Load("FacadeSample"). CreateInstance (facadeString);  
            ef.FileEncrypt("src.txt", "des.txt");  
            Console.Read();  
        }  
    }  

 

 

 

 

 

 

 

 

posted @ 2019-01-11 20:34  Archer-Fang  阅读(184)  评论(0编辑  收藏  举报