它通过引入1个外观角色来简化客户端与子系统里头的互动澳门威尼斯人网址,它经过引入一个外观剧中人物来简化客户端与子系统里面的并行

【学习难度:★☆☆☆☆,使用频率:★★★★★】 

【学习难度:★☆☆☆☆,使用作用:★★★★★】
一直出处:http://woquanke.com/books/gof/
梳理和学习:https://github.com/BruceOuyang/boy-design-pattern
简书日期: 2018/03/14
简书首页:https://www.jianshu.com/p/0fb891a7c5ed

外观格局是一种接纳作用十分高的结构型设计形式,它通过引入一个外观剧中人物来简化客户端与子系统之间的相互,为复杂性的子系统调用提供三个合并的进口,降低子系统与客户端的耦合度,且客户端调用格外便于。

 

浅显外观方式(一)

外观格局是一种选取成效十二分高的结构型设计形式,它通过引入3个外观剧中人物来简化客户端与子系统之间的相互,为复杂性的子系统调用提供壹个集合的进口,降低子系统与客户端的耦合度,且客户端调用卓殊便宜。

1.外观形式概述

不明白大家有没有比较过本身泡茶和去酒店喝茶的界别,如若是祥和泡茶要求活动准备茶叶、茶具和沸水,如图1(A)所示,而去饭店喝茶,最简便易行的方法就是跟饭铺服务员说想要一杯什么样的茶,是铁观世音、毛尖如故洞庭毛尖?正因为酒楼有服务员,顾客无须直接和茶叶、茶具、开水等互动,整个泡茶进度由服务员来形成,顾客只需与服务员交互即可,整个经过十一分简单省事,如图1(B)所示。

澳门威尼斯人网址 1

图1 两种喝茶格局示意图

在软件开发中,有时候为了做到一项较为复杂的功用,3个客户类须求和三个事情类交互,而那一个需要互相的业务类日常会作为多少个完好无缺出现,由于涉及到的类相比较多,导致使用时期码较为复杂,此时,尤其须要2个好像服务员一样的角色,由它来负担和七个业务类进行互动,而客户类只需与该类交互。外观情势通过引入二个新的外观类(Facade)来促成该效能,外观类充当了软件系统中的“服务员”,它为三个业务类的调用提供了一个统一的入口,简化了类与类之间的互相。在外观方式中,那个急需相互的事情类被称为子系统(Subsystem)。即使没有外观类,那么各种客户类要求和五个子系统之间举办复杂的相互,系统的耦合度将很大,如图2(A)所示;而引入外观类之后,客户类只需求从来与外观类交互,客户类与子系统之间原本的繁杂引用关系由外观类来促成,从而下跌了系统的耦合度,如图2(B)所示。

澳门威尼斯人网址 2

图2 外观情势示意图

外观方式中,一个子连串的外部与其中间的通讯通过1个合并的外观类进行,外观类将客户类与子系统的中间复杂性分隔开,使得客户类只需求与外观角色打交道,而不须求与子系统之中的不可胜言目标打交道。

外观形式定义如下:
外观格局:为子系统中的一组接口提供3个合并的进口。外观形式定义了一个高层接口,这几个接口使得这一子系统进一步便于采纳。
Facade Pattern: Provide a unified interface to a set of interfaces in a
subsystem. Facade defines a higher-level interface that makes the
subsystem easier to use.

外观情势又称为门面方式,它是一种对象结构型情势。外观方式是迪米特法则的一种具体贯彻,通过引入3个新的外观剧中人物可以减低原有系统的复杂度,同时下落客户类与子系统的耦合度。

2.外观格局结构与落成

2.1 情势结构

外观情势尚未贰个一般化的类图描述,平常使用如图2(B)所示示意图来代表外观情势。图3所示的类图也足以当做描述外观情势的结构图:

澳门威尼斯人网址 3

图3 外观格局结构图

由图3可见,外观形式涵盖如下五个角色:

(1)
Facade(外观角色):在客户端可以调用它的章程,在外观剧中人物中可以知道有关的(1个可能八个)子系统的意义和任务;在健康境况下,它将有着从客户端发来的央浼委派到对应的子系统去,传递给相应的子系统对象处理。

(2)
SubSystem(子系统角色):在软件系统中能够有一个恐怕七个子系统角色,每多个子系统可以不是2个单身的类,而是三个类的集纳,它完成子系统的效益;每1个子系统都可以被客户端直接调用,只怕被外观角色调用,它处理由外观类传过来的央求;子系统并不知道外观的留存,对于子系统而言,外观剧中人物唯有是其它二个客户端而已。

2.2 方式完毕

外观方式的要害目的在于降低系统的复杂程度,在面向对象软件系统中,类与类之间的关系更多,不只怕代表系统规划得越好,反而表示系统中类之间的耦合度太大,那样的系列在保安和改动时都紧缺灵活性,因为1个类的改观会促成多个类发生变化,而外观模式的引入在很大程度上下滑了类与类之间的耦合关系。引入外观格局之后,增加新的子系统可能移除子系统都分外有利于,客户类无须进行修改(或许极少的改动),只须要在外观类中加进或移除对子系统的引用即可。从那点来说,外观方式在一定水平上并不切合开闭原则,增添新的子系统必要对原始系统举行一定的改动,即使这么些修改工作量不大。

外观格局中所指的子系统是贰个广义的概念,它能够是三个类、三个功效模块、系统的三个组成部分或然多少个完好无缺的种类。子系统类寻常是局地业务类,落成了部分有血有肉的、独立的作业效能,其至高无上代码如下:

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所示,而去酒馆喝茶,最简易的章程就是跟茶楼服务员说想要一杯什么样的茶,是铁观世音菩萨、云南元江茶还是铁观音?正因为酒店有服务员,顾客无须直接和茶叶、茶具、开水等相互,整个泡茶进度由服务员来成功,顾客只需与服务员交互即可,整个经过分外简单省事,如图2所示。

澳门威尼斯人网址 4

图1

澳门威尼斯人网址 5

图2

在软件开发中,有时候为了成功一项较为复杂的效用,一个客户类须要和两个工作类交互,而这几个需要相互的业务类平日会作为三个完完全全出现,由于涉及到的类相比较多,导致使用时代码较为复杂,此时,尤其必要2个好像服务员一样的剧中人物,由它来承担和多少个事情类进行互动,而客户类只需与该类交互。外观情势通过引入3个新的外观类(Facade)来落到实处该意义,外观类充当了软件系统中的“服务员”,它为三个业务类的调用提供了一个统一的入口,简化了类与类之间的互相。在外观方式中,这几个必要互相的业务类被叫作子系统(Subsystem)。若是没有外观类,那么每一种客户类要求和多少个子系统里头开展复杂的相互,系统的耦合度将很大;而引入外观类之后,客户类只须求一贯与外观类交互,客户类与子系统之间原本的扑朔迷离引用关系由外观类来贯彻,从而下跌了系统的耦合度。

外观情势中,1个子系统的外表与其里面的通讯通过3个联结的外观类举办,外观类将客户类与子系统的其中复杂性分隔开,使得客户类只须要与外观角色打交道,而不须求与子系统内部的不在少数对象打交道。

外观情势定义如下:
外观情势:为子系统中的一组接口提供三个联结的进口。外观情势定义了1个高层接口,那个接口使得这一子系统进一步便于选用。

Facade Pattern:Provide a unified interface to a set of interfaces in
a subsystem. Facade defines a higher-level interface that makes the
subsystem easier to use.

外观方式又称之为门面情势,它是一种对象结构型情势。外观形式是迪米特法则的一种具体落到实处,通过引入一个新的外观剧中人物可以降低原有系统的复杂度,同时下落客户类与子系统的耦合度。

外观方式是一种接纳频率十一分高的结构型设计格局,它经过引入1个外观角色来简化客户端与子系统里面的互相,为复杂性的子系统调用提供二个集合的输入,下跌子系统与客户端的耦合度,且客户端调用分外便于。

初阶外观形式(二)

3.外观格局采纳实例

上边通过三个用到实例来一发学习和驾驭外观方式。

3.1 实例证实

某软件商店欲开发贰个可使用于两个软件的文书加密模块,该模块可以对文件中的数据进行加密并将加密事后的数额存储在3个新文件中,具体的流水线包涵多少个部分,分别是读取源文件、加密、保存加密从此的文本,其中,读取文件和保存文件使用流来完成,加密操作通过求模运算完成。那七个操作相对独立,为了落实代码的单身重用,让规划更合乎单一义务规范,那多少个操作的事情代码封装在多个例外的类中。

现使用外观格局设计该公文加密模块。

3.2 实例类图

经过分析,本实例结构图如图4所示。

澳门威尼斯人网址 6

图4 文件加密模块结构图

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

3.3 实例代码

(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();  
            System.out.println(sb.ToString());  
        }  
        catch(FileNotFoundException e)   
        {  
            System.out.println("文件不存在!");  
        }  
        catch(IOException e)   
        {  
            System.out.println("文件操作错误!");  
        }  
        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;  
        }  
        System.out.println(es);  
        return es;  
    }  

}  

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

class FileWriter  
{  
    public void Write(string encryptStr,string fileNameDes)   
    {  
        System.out.println("保存密文,写入文件。");  
        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)   
        {  
            System.out.println("文件不存在!");  
        }  
        catch(IOException e)   
        {  
            System.out.println(e.Message);  
            System.out.println("文件操作错误!");  
        }          
    }  
} 

(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 Client  
{  
    public static void Main(string[] args)  
    {  
        EncryptFacade ef = new EncryptFacade();  
        ef.FileEncrypt("src.txt", "des.txt");  
        Console.Read();  
    }  
}  

编译并运营程序,输出结果如下:

读取文件,获取明文:Hello world!
数据加密,将明文转换为密文:233364062325
保存密文,写入文件。

在本实例中,对文件src.txt中的数据开展加密,该公文内容为“Hello
world!”,加密之后将密文保存到另贰个文本des.txt中,程序运转后保存在文书中的密文为“233364062325”。在加密类CipherMachine中,采取求模运算对公开举办加密,将公开中的每三个字符除以三个平头(本例中为7,可以由用户来展开设置)后取余数作为密文。

2. 外观方式结构与贯彻

 

浅显外观方式(三)

4.华而不实外观类

在业内的外观形式协会图中,如若急需扩展、删除或撤换与外观类交互的子系统类,必须修改外观类或客户端的源代码,那将违反开闭原则,因而可以通过引入抽象外观类来对系统进行立异,在一定水平上可以消除该难点。在引入抽象外观类之后,客户端可以本着抽象外观类进行编程,对于新的政工需求,不必要修改原有外观类,而对应扩张三个新的有血有肉外观类,由新的有血有肉外观类来涉及新的子系统对象,同时经过改动配置文件来达到不修改任何源代码并转换外观类的目的。

上边通过3个具体实例来上学如何使用抽象外观类:

假使在利用实例“文件加密模块”中必要转移2个加密类,不再行使原有的依据求模运算的加密类CipherMachine,而改为依据移动运算的新加密类NewCipherMachine,其代码如下:

class NewCipherMachine  
{  
    public string Encrypt(string plainText)   
    {  
        Console.Write("数据加密,将明文转换为密文:");  
        string es = "";  
        int key = 10;//设置密钥,移位数为10  
        char[] chars = plainText.ToCharArray();  
        foreach(char ch in chars)   
        {  
            int temp = Convert.ToInt32(ch);  
            //小写字母移位  
            if (ch >= 'a' && ch <= 'z') {  
                temp += key % 26;  
                if (temp > 122) temp -= 26;  
                if (temp < 97) temp += 26;  
            }  
            //大写字母移位  
            if (ch >= 'A' && ch <= 'Z') {  
                temp += key % 26;  
                if (temp > 90) temp -= 26;  
                if (temp < 65) temp += 26;  
            }  
            es += ((char)temp).ToString();  
        }  
        System.out.println(es);  
        return es;  
    }  
} 

比方不增添新的外观类,只可以通过改动原有外观类EncryptFacade的源代码来促成加密类的更换,将本来的对CipherMachine类型对象的引用改为对NewCipherMachine类型对象的引用,那违背了开闭原则,由此必要经过扩大新的外观类来落到实处对子系统对象引用的改变。

如果伸张一个新的外观类NewEncryptFacade来与FileReader类、FileWriter类以及新扩大的NewCipherMachine类举办互动,就算原有系统类库无须做其余修改,不过因为客户端代码中原来针对EncryptFacade类举行编程,未来急需改为NewEncryptFacade类,由此须要修改客户端源代码。

怎么着在不修改客户端代码的前提下利用新的外观类呢?化解办法之一是:引入二个浮泛外观类,客户端针对抽象外观类编程,而在运作时再鲜明具体外观类,引入抽象外观类之后的文书加密模块结构图如图5所示:

澳门威尼斯人网址 7

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

在图5中,客户类Client针对抽象外观类AbstractEncryptFacade举行编程,AbstractEncryptFacade代码如下:

public abstract class AbstractEncryptFacade  
{  
    public abstract void FileEncrypt(string fileNameSrc, string fileNameDes);  
} 

增产具体加密外观类NewEncryptFacade代码如下:

class NewEncryptFacade extends 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="FacadeSample.NewEncryptFacade"/>  
  </appSettings>  
</configuration>

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

public class Program  
{  
    public 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();  
    }  
}  

编译并运转程序,输出结果如下:

读取文件,获取明文:Hello world!
数据加密,将明文转换为密文:Rovvy gybvn!
保存密文,写入文件。

土生土长外观类EncryptFacade也需作为抽象外观类AbstractEncryptFacade类的子类,更换实际外观类时只需修改配置文件,无须修改源代码,符合开闭原则。

5.外观形式功效与适用场景

外观格局是一种采纳频率拾贰分高的设计方式,它经过引入八个外观剧中人物来简化客户端与子系统里面的互动,为复杂性的子系统调用提供三个合并的输入,使子系统与客户端的耦合度下落,且客户端调用极度有利。外观形式并不给系统增添其他新作用,它只是是简化调用接口。在大概全数的软件中都可以找到外观形式的运用,如绝大部分B/S系统都有多少个首页或者导航页面,大部分C/S系统都提供了菜单或然工具栏,在那里,首页和导航页面就是B/S系统的外观角色,而菜单和工具栏就是C/S系统的外观角色,通过它们用户能够长足访问子系统,下跌了系统的复杂程度。所有涉及到与多少个工作对象交互的现象都得以考虑采纳外观形式展开重构。

5.1 形式亮点

外观方式的紧要优点如下:

(1)
它对客户端屏蔽了子系统组件,减弱了客户端所需处理的指标数目,并使得子系统利用起来更为便于。通过引入外观情势,客户端代码将变得很粗略,与之提到的靶子也很少。

(2)
它完成了子系统与客户端之间的松耦合关系,那使得子系统的生成不会潜移默化到调用它的客户端,只须求调动外观类即可。

(3)
二个子系统的修改对其他子系统绝非任何影响,而且子系统里头变化也不会潜移默化到外观对象。

5.2 格局缺点

外观情势的基本点弱点如下:

(1)
不可以很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限定则缩减了可变性和灵活
性。

(2)
即使规划不当,增加新的子系统或者要求修改外观类的源代码,违背了开闭原则。

5.3 形式适用场景

在以下境况下得以考虑采纳外观形式:

(1) 当要为访问一多元复杂的子系统提供2个简单入口时能够接纳外观形式。

(2)
客户端程序与两个子系统里面存在很大的倚重。引入外观类可以将子系统与客户端解耦,从而抓好子系统的独立性和可移植性。

(3)
在层次化结构中,可以拔取外观情势定义系统中每一层的入口,层与层之间不直接发生联系,而透过外观类建立联系,下降层之间的耦合度。

2.1 方式协会

外观情势尚未3个一般化的类图描述,常常使用如图2(B)所示示意图来表示外观方式。图3所示的类图也可以作为描述外观方式的布局图:

澳门威尼斯人网址 8

图3 外观情势结构图
由图3可知,外观形式涵盖如下七个角色:

  • Facade(外观角色):在客户端可以调用它的法子,在外观角色中得以知道有关的(3个照旧两个)子系统的功效和权责;在健康情状下,它将具备从客户端发来的央浼委派到相应的子系统去,传递给相应的子系统对象处理。

  • SubSystem(子系统剧中人物):在软件系统中得以有壹个如故多少个子系统角色,每多个子系统能够不是贰个单独的类,而是八个类的集纳,它完毕子系统的效率;每二个子连串都可以被客户端直接调用,或然被外观角色调用,它处理由外观类传过来的乞请;子系统并不知道外观的留存,对于子系统而言,外观角色只有是别的二个客户端而已。

1. 外观情势概述

     
不领悟大家有没有相比较过本身泡茶和去饭铺喝茶的区分,如若是友善泡茶须求活动准备茶叶、茶具和开水,如图1(A)所示,而去酒店喝茶,最简易的法子就是跟茶楼服务员说想要一杯什么样的茶,是铁观世音、毛尖仍旧黄芽茶?正因为酒店有服务员,顾客无须直接和茶叶、茶具、开水等相互,整个泡茶进度由服务员来成功,顾客只需与服务员交互即可,整个经过分外简单省事,如图1(B)所示。

澳门威尼斯人网址 9

图1 三种喝茶情势示意图

      
在软件开发中,有时候为了完成一项较为复杂的功能,壹个客户类需求和三个事情类交互,而那么些须要相互的业务类平日会作为3个完整出现,由于涉及到的类相比多,导致使用时期码较为复杂,此时,尤其须求多少个接近服务员一样的角色,由它来担负和多个工作类进行交互,而客户类只需与该类交互。外观形式通过引入一个新的外观类(Facade)来促成该效用,外观类充当了软件系统中的“服务员”,它为八个业务类的调用提供了一个集合的输入,简化了类与类之间的互相。在外观情势中,那么些急需互相的事体类被称之为子系统(Subsystem)。如若没有外观类,那么每一种客户类需求和多少个子系统里面展开复杂的并行,系统的耦合度将很大,如图2(A)所示;而引入外观类之后,客户类只必要一直与外观类交互,客户类与子系统之间原有的繁杂引用关系由外观类来促成,从而下降了系统的耦合度,如图2(B)所示。

澳门威尼斯人网址 10

图2 外观情势示意图

       外观情势中,3个子序列的表面与其中间的通讯通过八个合并的外观类进行,外观类将客户类与子系统的里边复杂性分隔开,使得客户类只要求与外观角色打交道,而不要求与子系统里面的重重目的打交道。

      外观格局定义如下:

 

外观模式:为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

Facade Pattern: Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

 

 

     
外观情势又称作门面方式,它是一种对象结构型形式。外观格局是迪米特法则的一种具体贯彻,通过引入几个新的外观角色可以降低原有系统的复杂度,同时降低客户类与子系统的耦合度。

 

2.2 格局达成

外观情势的重宗意在下降系统的复杂程度,在面向对象软件系统中,类与类之间的关系更多,不可以代表系统规划得越好,反而表示系统中类之间的耦合度太大,那样的系列在保安和修改时都缺乏灵活性,因为1个类的更改会造成多个类发生变化,而外观情势的引入在很大程度上跌落了类与类之间的耦合关系。引入外观方式之后,增添新的子系统或许移除子系统都极度方便,客户类无须进行改动(恐怕极少的修改),只须求在外观类中加进或移除对子系统的引用即可。从那点来说,外观方式在自然水准上并不吻合开闭原则,伸张新的子系统须求对本来系统开展一定的修改,固然这么些修改工作量不大。

外观格局中所指的子系统是贰个广义的概念,它可以是3个类、一个功能模块、系统的多少个组成部分恐怕二个总体的体系。子系统类常常是一对业务类,达成了一部分切实可行的、独立的事务职能。
//TODO

2. 外观情势协会与已毕

2.1 格局协会

      外观形式尚未2个一般化的类图描述,经常采纳如图2(B)所示示意图来代表外观形式。图3所示的类图也可以用作描述外观格局的布局图:

澳门威尼斯人网址 11

图3 外观格局结构图

       由图3可见,外观形式涵盖如下八个角色:

      (1)
Facade(外观剧中人物):
在客户端可以调用它的格局,在外观角色中得以领会有关的(多个只怕多少个)子系统的成效和任务;在正规情形下,它将具有从客户端发来的呼吁委派到相应的子系统去,传递给相应的子系统对象处理。

      (2)
SubSystem(子系统剧中人物):
在软件系统中得以有贰个如故多少个子系统剧中人物,每二个子序列可以不是壹个独立的类,而是壹个类的联谊,它完结子系统的功用;每多个子系统都足以被客户端直接调用,大概被外观角色调用,它处理由外观类传过来的呼吁;子系统并不知道外观的存在,对于子系统而言,外观剧中人物唯有是其余一个客户端而已。

 

2.2 方式达成

     
外观格局的第贰意在下落系统的复杂程度,在面向对象软件系统中,类与类之间的关联更多,不能够代表系统规划得越好,反而表示系统中类之间的耦合度太大,那样的连串在保护和修改时都缺乏灵活性,因为二个类的改观会促成几个类暴发变化,而外观格局的引入在很大程度上下跌了类与类之间的耦合关系。引入外观格局之后,增添新的子系统或许移除子系统都极度方便,客户类无须举行改动(可能极少的修改),只须要在外观类中追加或移除对子系统的引用即可。从这点来说,外观形式在肯定程度上并不适合开闭原则,增加新的子系统要求对原本系统进行自然的修改,即使那个修改工作量不大。

     
外观方式中所指的子系统是贰个广义的定义,它可以是2个类、三个成效模块、系统的三个组成部分恐怕3个完整的系统。子系统类平日是一些业务类,落成了某个切实可行的、独立的作业功用,其优良代码如下:

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();  

    }  
}  

 

3. 外观方式采纳实例

       下边通过三个拔取实例来更为读书和驾驭外观情势。

 

       1. 实例证实

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

       现使用外观模式设计该文件加密模块。

      

       2. 实例类图

       通过分析,本实例结构图如图4所示。

澳门威尼斯人网址 12

图4 文件加密模块结构图

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

 

       3. 实例代码

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

//FileReader.cs  
using System;  
using System.Text;  
using System.IO;  

namespace FacadeSample  
{  
    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:数据加密类,充当子系统类。

//CipherMachine.cs  
using System;  
using System.Text;  

namespace FacadeSample  
{  
    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:文件保存类,充当子系统类。

//FileWriter.cs  
using System;  
using System.IO;  
using System.Text;  

namespace FacadeSample  
{  
    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:加密外观类,充当外观类。

// EncryptFacade.cs  
namespace FacadeSample  
{  
    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:客户端测试

//Program.cs  
using System;  

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

 4. 结出及分析

       编译并运转程序,输出结果如下:

 

读取文件,获取明文:Hello world!

数据加密,将明文转换为密文:233364062325

保存密文,写入文件。

 

 

       在本实例中,对文件src.txt中的数据举办加密,该公文内容为“Hello
world!”,加密然后将密文保存到另3个文件des.txt中,程序运营后保存在文书中的密文为“233364062325”。在加密类CipherMachine中,接纳求模运算对公开进行加密,将公开中的每一个字符除以二个整数(本例中为7,可以由用户来开展设置)后取余数作为密文。

4. 空洞外观类

      在标准的外观格局社团图中,假如急需充实、删除或撤换与外观类交互的子系统类,必须修改外观类或客户端的源代码,那将违反开闭原则,因而可以通过引入空洞外观类来对系统举行革新,在必然水平上得以化解该难题。在引入抽象外观类之后,客户端可以针对抽象外观类举办编程,对于新的事情必要,不须求修改原有外观类,而对应扩张三个新的切实可行外观类,由新的切实可行外观类来涉及新的子系统对象,同时经过改动配置文件来落成不改动任何源代码并转移外观类的目标。

      上边通过多少个现实实例来读书怎么采用抽象外观类:

     
即使在行使实例“文件加密模块”中须求更换二个加密类,不再利用原有的基于求模运算的加密类CipherMachine,而改为基于移动运算的新加密类NewCipherMachine,其代码如下:

using System;  

namespace FacadeSample  
{  
    class NewCipherMachine  
    {  
        public string Encrypt(string plainText)   
        {  
            Console.Write("数据加密,将明文转换为密文:");  
            string es = "";  
            int key = 10;//设置密钥,移位数为10  
            char[] chars = plainText.ToCharArray();  
            foreach(char ch in chars)   
            {  
                int temp = Convert.ToInt32(ch);  
                //小写字母移位  
                if (ch >= 'a' && ch <= 'z') {  
                    temp += key % 26;  
                    if (temp > 122) temp -= 26;  
                    if (temp < 97) temp += 26;  
                }  
                //大写字母移位  
                if (ch >= 'A' && ch <= 'Z') {  
                    temp += key % 26;  
                    if (temp > 90) temp -= 26;  
                    if (temp < 65) temp += 26;  
                }  
                es += ((char)temp).ToString();  
            }  
            Console.WriteLine(es);  
            return es;  
        }  
    }  
}  

 尽管不增添新的外观类,只好通过改动原有外观类EncryptFacade的源代码来促成加密类的更换,将原始的对CipherMachine类型对象的引用改为对NewCipherMachine类型对象的引用,这违反了开闭原则,因而须求经过增添新的外观类来落到实处对子系统对象引用的转移。

       就算增添一个新的外观类NewEncryptFacade来与File里德r类、FileWriter类以及新扩张的NewCipherMachine类举办互相,固然原有系统类库无须做另外修改,可是因为客户端代码中原本针对EncryptFacade类进行编程,以后急需改为NewEncryptFacade类,因而须要修改客户端源代码。

       怎么着在不改动客户端代码的前提下接纳新的外观类呢?化解方法之一是:引入贰个浮泛外观类,客户端针对抽象外观类编程,而在运维时再鲜明具体外观类,引入抽象外观类之后的公文加密模块结构图如图5所示:

澳门威尼斯人网址 13

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

      
在图5中,客户类Client针对抽象外观类AbstractEncryptFacade举办编程,AbstractEncryptFacade代码如下:

namespace FacadeSample  
{  
    abstract class AbstractEncryptFacade  
    {  
        public abstract void FileEncrypt(string fileNameSrc, string fileNameDes);  
    }  
}  

新增具体加密外观类NewEncryptFacade代码如下:

namespace FacadeSample  
{  
    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中蕴藏了具体外观类的类名,代码如下:

[csharp] view
plain
 copy

 

  1. <?xml version=”1.0″ encoding=”utf-8″ ?>  
  2. <configuration>  
  3.   <appSettings>  
  4.     <add key=”facade” value=”FacadeSample.NewEncryptFacade”/>  
  5.   </appSettings>  
  6. </configuration>  

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

using System;  
using System.Configuration;  
using System.Reflection;  

namespace FacadeSample  
{  
    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();  
        }  
    }  
}  

编译并运营程序,输出结果如下:

 

读取文件,获取明文:Hello world!

数据加密,将明文转换为密文:Rovvy gybvn!

保存密文,写入文件。

 

 

      
原有外观类EncryptFacade也需作为抽象外观类AbstractEncryptFacade类的子类,更换实际外观类时只需修改配置文件,无须修改源代码,符合开闭原则。

 

5. 外观形式效率与适用场景

      
外观情势是一种采用功用十一分高的设计形式,它经过引入一个外观角色来简化客户端与子系统之间的相互,为复杂性的子系统调用提供1个联合的入口,使子系统与客户端的耦合度下跌,且客户端调用格外方便。外观格局并不给系统增添其他新效用,它仅仅是简化调用接口。在大概全数的软件中都可以找到外观形式的施用,如绝一大半B/S系统都有一个首页只怕导航页面,大多数C/S系统都提供了菜单或者工具栏,在那里,首页和导航页面就是B/S系统的外观剧中人物,而菜单和工具栏就是C/S系统的外观角色,通过它们用户可以长足访问子系统,降低了系统的复杂程度。全体涉及到与三个业务对象交互的场所都得以设想使用外观形式展开重构。

 

5.1 情势亮点

       外观格局的主要性优点如下:

      
(1) 它对客户端屏蔽了子系统组件,裁减了客户端所需处理的对象数目,并使得子系统接纳起来特别不难。通过引入外观方式,客户端代码将变得很粗略,与之提到的对象也很少。

      
(2) 它落成了子系统与客户端之间的松耦合关系,那使得子系统的扭转不会影响到调用它的客户端,只必要调整外观类即可。

       (3) 2个子系列的改动对其余子系统绝非此外影响,而且子系统里头变化也不会潜移默化到外观对象。

 

5.2 情势缺点

       外观格局的第叁弱点如下:

      
(1) 不能很好地限制客户端间接使用子系统类,即便对客户端访问子系统类做太多的界定则缩减了可变性和灵活
性。

      
(2) 假若规划不当,伸张新的子系统只怕必要修改外观类的源代码,违背了开闭原则。

 

5.3 形式适用场景

       在偏下情形下得以考虑采取外观方式:

      
(1) 当要为访问一体系复杂的子系统提供2个简便入口时方可利用外观格局。

      
(2) 客户端程序与多个子系统里头存在很大的依靠。引入外观类可以将子系统与客户端解耦,从而增强子系统的独立性和可移植性。

      
(3) 在层次化结构中,可以动用外观方式定义系统中每一层的输入,层与层之间不直接发生联系,而通过外观类建立联系,下落层之间的耦合度。

 

【作者:刘伟 http://blog.csdn.net/lovelion

 

 

相关文章