精华内容
下载资源
问答
  • Facade模式框架源码

    千次阅读 2020-11-25 20:59:57
    1、Facade模式概念 2、优缺点 3、类图 4、开源框架引例 4.1 common-beanutils * Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.commons.beanutils....

    目录

    1、Facade模式概念

    2、优缺点

    3、类图 

    4、开源框架引例

    4.1 common-beanutils

    4.2 druid

     


    参考文档:外观模式

    1、Facade模式概念

             外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

    这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

    2、优缺点

    优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。

    缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

    使用场景: 1、为复杂的模块或子系统提供外界访问的模块。 2、子系统相对独立。 3、预防低水平人员带来的风险。

    3、类图 

     

     

     

       

    4、开源框架引例

    4.1 common-beanutils

     * Licensed to the Apache Software Foundation (ASF) under one or more
    package org.apache.commons.beanutils.converters;
    
    import org.apache.commons.beanutils.Converter;
    
    /**
     * Provides a facade for {@link Converter} implementations
     * preventing access to any public API in the implementation,
     * other than that specified by {@link Converter}.
     * <p />
     * This implementation can be used to prevent registered {@link Converter}
     * implementations that provide configuration options from being
     * retrieved and modified.
     *
     * @version $Id: ConverterFacade.java 1632171 2014-10-15 20:15:17Z ggregory $
     * @since 1.8.0
     */
    public final class ConverterFacade implements Converter {
    
        private final Converter converter;
    
        /**
         * Construct a converter which delegates to the specified
         * {@link Converter} implementation.
         *
         * @param converter The converter to delegate to
         */
        public ConverterFacade(final Converter converter) {
            if (converter == null) {
                throw new IllegalArgumentException("Converter is missing");
            }
            this.converter = converter;
        }
    
        /**
         * Convert the input object into an output object of the
         * specified type by delegating to the underlying {@link Converter}
         * implementation.
         *
         * @param <T> The result type of the conversion
         * @param type Data type to which this value should be converted
         * @param value The input value to be converted
         * @return The converted value.
         */
        public <T> T convert(final Class<T> type, final Object value) {
            return converter.convert(type, value);
        }
    
        /**
         * Provide a String representation of this facade implementation
         * sand the underlying {@link Converter} it delegates to.
         *
         * @return A String representation of this facade implementation
         * sand the underlying {@link Converter} it delegates to
         */
        @Override
        public String toString() {
            return "ConverterFacade[" + converter.toString() + "]";
        }
    
    }
    


    4.2 druid

    /**
     * 监控相关的对外数据暴露
     * 
     * 1. 为了支持jndi数据源本类内部调用druid相关对象均需要反射调用,返回值也应该是Object,List&lt;Object&gt;,Map&lt;String,Object&gt;等无关于druid的类型
     * 2. 对外暴露的public方法都应该先调用init(),应该有更好的方式,暂时没想到
     * 
     * @author sandzhang[sandzhangtoo@gmail.com]
     */
    public final class DruidStatManagerFacade {
    
        private final static DruidStatManagerFacade instance    = new DruidStatManagerFacade();
        private boolean                             resetEnable = true;
        private final AtomicLong                    resetCount  = new AtomicLong();
    
        private DruidStatManagerFacade(){
        }
    
        public static DruidStatManagerFacade getInstance() {
            return instance;
        }
    
        private Set<Object> getDruidDataSourceInstances() {
            return DruidDataSourceStatManager.getInstances().keySet();
        }

     

    展开全文
  • Facade模式

    2009-05-25 14:16:29
    Facade模式 Facade模式 一、概述 Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用。 实际应用中,我们在对付一些老旧的code(尤其是将C的...

    Facade模式  Facade模式
      一、概述
      Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用。
      实际应用中,我们在对付一些老旧的code(尤其是将C的代码转成C++代码)或者即便不是老旧code,但涉及多个子系统时,除了重写全部代码(对于老旧code而言),我们还可能采用这样一种策略:
      重新进行类的设计,将原来分散在源码中的类/结构及方法重新组合,形成新的、统一的接口,供上层应用使用。
      这在某种意义上与Adapter及Proxy有类似之处,但是,Proxy(代理)注重在为Client-Subject提供一个访问的中间层,如CORBA可为应用程序提供透明访问支持,使应用程序无需去考虑平台及网络造成的差异及其它诸多技术细节;Adapter(适配器)注重对接口的转换与调整;而Facade所面对的往往是多个类或其它程序单元,通过重新组合各类及程序单元,对外提供统一的接口/界面。
      三、应用
      在遇到以下情况使用Facade模式:
      1、当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。
      Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。
      2、客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
      3、当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点,如果子系统之间是相互依赖的,你可以让它们仅通过Facade进行通讯,从而简化了它们之间的依赖关系。
      四、优缺点
      Facade模式有下面一些优点:
      1、它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
      2、它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。
      松耦合关系使得子系统的组件变化不会影响到它的客户。Facade模式有助于建立层次结构系统,也有助于对对象之间的依赖关系分层。Facade模式可以消除复杂的循环依赖关系。这一点在客户程序与子系统是分别实现的时候尤为重要。
      在大型软件系统中降低编译依赖性至关重要。在子系统类改变时,希望尽量减少重编译工作以节省时间。用Facade可以降低编译依赖性,限制重要系统中较小的变化所需的重编译工作。Facade模式同样也有利于简化系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。
      3、如果应用需要,它并不限制它们使用子系统类。因此你可以在系统易用性和通用性之间加以选择。

     

    代码的“门面”——模式系列谈之Facade模式
    <!-- #EndEditable -->
    <!-- #BeginEditable "2" --><!-- #EndEditable -->
    <!-- #BeginEditable "3" -->

    看到“门面”这个词,大家一定都觉得很熟悉。不错,这个词正是借用了我们日常生活中的“门面”的概念。日常生活中的“门面”,正是我们买东西的地方。因此可以这么说,“门面”就是这么一个地方,它们跟各种商品的生产商打交道,收集商品后,再卖给我们。换句话说,如果没有“门面”,我们将不得不直接跟各种各样的生产商买商品;而有了“门面”,我们要买东西,直接跟“门面”打交道就可以了。

    Facade模式正是这样一个“门面”:我们本来需要与后台的多个类或者接口打交道,而Facade模式是客户端和后台之间插入一个中间层——门面,这个门面跟后台的多个类或接口打交道,而客户端只需要跟门面打交道即可。

    使用Facade模式可以说是后台设计和编码人员的一个必备素质。我不止碰到过一个这样的后台开发人员,他们认为只要把后台功能完成了就万事大吉,而没有站在后台使用者的角度来看一看自己写出来的代码。其实,我们写出来的后台代码是要给别人使用的,所以我们提供给使用者的接口要越简单越好,这不单是对使用者好,同时对开发者也是好处多多的,至少你的接口简单了,你和使用者的交流就容易了。

    而Facade模式中的Facade类正是这样一个用户接口,它和后台中的多个类产生依赖关系,而后台的客户类则只跟Facade类产生依赖关系。为什么要这么做?其中的原因十分简单:后台的开发者熟悉他自己开发的各个类,也就容易解决和多个类的依赖关系,而后台的使用者则不太熟悉后台的各个类,不容易处理和它们之间的依赖;因此,后台的开发者自己在Facade类中解决了与后台多个类之间的依赖,后台的使用者只需要处理和Facade类的依赖即可。

    好了,闲话少说。我们下面就以几个具体的例子来看一看Facade模式是怎么使用的。实际编程中,能使用到Facade模式的情况有很多,以下就分两种情况来具体说一说Facade模式的使用。可能还会有其他的情况,大家在实践中也可以加以补充。

    第一种情况,客户类要使用的功能分布在多个类中,这些类可能相互之间没有什么关系;客户在使用后台的时候,必须先初始化要使用到的功能所在的类,然后才能使用。这时候,适合将这些功能集中在一个Facade类里,还可以替用户做一些初始化的工作,以减轻用户的负担。
    例如,以商店为例。假如商店里出售三种商品:衣服、电脑和手机。这三种商品都是由各自的生产厂商卖出的,如下:
    public class CoatFactory
    {
    public Coat saleCoat()
    {
    ……
    return coat;
    }
    ……
    }

    然后是电脑的厂家类:

    public class ComputerFactory
    {
    public Computer saleComputer()
    {
    ……
    return computer;
    }
    ……
    }

    最后是手机商类:

    public class MobileFactory
    {
    public Mobile saleMobile()
    {
    ……
    return mobile;
    }
    ……
    }


    如果没有商店,我们就不得不分别跟各自的生产商打交道,如下:

    //买衣服
    CoatFactory coatFactory = new CoatFactory();
    coatFactory.saleCoat();
    //买电脑
    ComputerFactory computerFactory = new ComputerFactory();
    computerFactory.saleComputer();
    //买手机
    MobileFactory mobileFactory = new MobileFactory();
    mobileFactory.saleMobile();


    对我们顾客来说,和这么多的厂家类打交道,这显然是够麻烦的。


    这样,我们就需要创建一个商店类了,让商店类和这些厂家打交道,我们只和商店类打交道即可,如下:

    public class Store
    {
    public Coat saleCoat()
    {
    CoatFactory coatFactory = new CoatFactory();
    return coatFactory.saleCoat();
    }
    public Computer saleComputer()
    {
    ComputerFactory computerFactory = new ComputerFactory();
    return computerFactory.saleComputer();
    }
    public Mobile saleMobile()
    {
    MobileFactory mobileFactory = new MobileFactory();
    return mobileFactory.saleMobile();
    }
    }


    好了,现在我们要买东西,不用去跟那么多的厂家类打交道了。

    Store store =new Store();
    //买衣服
    store.saleCoat();
    //买电脑
    store.saleComputer();
    //买手机
    store.saleMobile();


    呵呵,这样对我们客户类来说,是不是简单多了。

    第二种情况客户要完成的某个功能,可能需要调用后台的多个类才能实现,这时候特别要使用Facade模式。不然,会给客户的调用带来很大的麻烦。请看下面的例子。

    我经常看到后台编码人员,强迫它们的使用者写出如下的代码:

    ……
    String xmlString = null;
    int result = 0;
    try
    {
    xmlString = gdSizeChart.buildDataXML(incBean);


    String path = "D:/Eclipse3.0/workspace/PLMSuite/AppWeb/PM/productSpecification/gridfile.xml";
    File f = new File(path);
    PrintWriter out = new PrintWriter(new FileWriter(f));
    out.print(xmlString);
    out.close();
    System.out.println("\r\n\r\n sumaryAction" + xmlString + "\r\n\r\n");
    request.setAttribute("xmlString", xmlString);
    }
    catch(Exception ex)
    {
    ex.printStackTrace();
    }


    这段代码前面即省略号省略掉的一部分是客户类调用后台的一部分代码,是一个相对独立的功能。后面这一部分也是一个相对独立的功能,而后台代码设计人员却把这个功能留给客户类自己来实现。

    我就很怀疑,让客户类做这么多事情,到底要你的后台做什么?你还不如直接把所有的事情都给客户类做了得了。因为,你后台做了一半,剩下的一部分给客户类做,客户类根本就不明白怎么回事,或者说他不清楚你的思路,这样做下去更加困难。可能这点逻辑对你来说,很简单。但使用者不明白你的思路啊,他不知道来龙去脉,怎么往下写?

    如果在这里有一个Facade类,让它来做不该由客户类来做的事,是不是简单多了呢?如下是一个Facade类:

    public class Facade
    {
    public static void doAll(PE_MeasTableExdBean incBean, HttpServletRequest request)
    {
    ……
    request.setAttribute(“xmlString”,Facade.getFromOut(incBean));
    }
    private static String getFromOut(PE_MeasTableExdBean incBean)
    {
    try
    {
    xmlString = gdSizeChart.buildDataXML(incBean);


    String path = "D:/Eclipse3.0/workspace/PLMSuite/AppWeb/PM/productSpecification/gridfile.xml";
    File f = new File(path);
    PrintWriter out = new PrintWriter(new FileWriter(f));
    out.print(xmlString);
    out.close();
    System.out.println("\r\n\r\n sumaryAction" + xmlString + "\r\n\r\n");
    return xmlString;
    }
    catch(Exception ex)
    {
    ex.printStackTrace();
    return null;
    }
    }
    }

    那么客户类的调用就是下面的样子:

    Facade.doAll(incBean,request);


    这样,客户是不是轻松多了?值得注意的是,Facade类中的getFromOut方法其实不应该在Facade类中,本文为了简单起见而放在了这个类中,对Facade类来说是不符合单一职责原则的。

    最后总结一下第二种情况的模式。后台为实现某一个功能有如下类:

    public class ClassA
    {
    public void doA()
    {
    ……
    }
    ……
    }
    public class ClassB
    {
    public void doB()
    {
    ……
    }
    ……
    }
    public class ClassC
    {
    public void doC()
    {
    ……
    }
    ……
    }

    如果客户类需要这样调用:

    ……
    ClassA a = new ClassA();
    a.doA();
    ClassB b = new ClassB();
    b.doB();
    ClassC c = new ClassC();
    c.doC();
    ……


    那么就适合做一个Facade类,来替客户类来完成上述的功能,如下:

    public class Facade
    {
    public void doAll()
    {
    ClassA a = new ClassA();
    a.doA();
    ClassB b = new ClassB();
    b.doB();
    ClassC c = new ClassC();
    c.doC();
    }
    }


    则客户类的调用如下:

    ……
    Facade Facade = new Facade();
    Facade.doAll();
    ……

    文章出自:http://www.uml.org.cn/sjms/200603201.htm    http://baike.baidu.com/view/1151448.htm

    展开全文
  • 简单工厂模式4简单工厂模式的主要优缺点简单工厂模式的应用场景2. 工厂方法模式5工厂模式的主要优缺点:工厂模式的主要应用场景3. 抽象工厂模式5抽象工厂模式的主要优缺点:抽象工厂模式的主要应用场景4. 原型模式3...

    design-patterns
    主要参考:

    文章目录

    面向对象设计模式的六(7)大原则

    1. 开闭原则(Open Close Principle)

      开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

    2. 里氏代换原则(Liskov Substitution Principle)

      里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

    3. 依赖倒置原则(Dependence Inversion Principle)

      这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

    4. 接口隔离原则(Interface Segregation Principle)

      这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

    5. 迪米特法则,又称最少知道原则(Demeter Principle)

      最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

    6. 合成复用原则(Composite Reuse Principle)

      合成复用原则是指:尽量使用对象组合、聚合、关联,而不是继承来达到复用的目的。

    7. 单一职责原则(Single-Responsibility Principle ):

      1. 一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中
      2. 就一个类而言,应该仅有一个引起它变化的原因。

    创建型模式

    创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。

    创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。

    包含模式

    • 简单工厂模式(Simple Factory)

      重要程度:4 (5为满分)

    • 工厂方法模式(Factory Method)

      重要程度:5

    • 抽象工厂模式(Abstract Factory)

      重要程度:5

    • 建造者模式(Builder)

      重要程度:2

    • 原型模式(Prototype)

      重要程度:3

    • 单例模式(Singleton)

      重要程度:4

    1. 简单工厂模式4

    在这里插入图片描述

    简单工厂模式的主要优缺点

    1. 简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,
    2. 但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码(违反开闭原则),而且产品较多时,工厂方法代码将会非常复杂。

    简单工厂模式的应用场景

    1. 简单工厂模式适用情况包括:工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。

    2. 工厂方法模式5

    工厂方法(FactoryMethod)模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。

    工厂模式-日志记录实例 类图
    在这里插入图片描述
    在这里插入图片描述

    工厂模式的主要优缺点:

    1. 工厂方法模式的主要优点是增加新的产品类时无须修改现有系统,并封装了产品对象的创建细节,系统具有良好的灵活性和可扩展性;
    2. 其缺点在于增加新产品的同时需要增加新的工厂,导致系统类的个数成对增加,在一定程度上增加了系统的复杂性。

    工厂模式的主要应用场景

    1. 工厂方法模式适用情况包括:一个类不知道它所需要的对象的类;一个类通过其子类来指定创建哪个对象;将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。

    3. 抽象工厂模式5

    抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
    在这里插入图片描述
    在这里插入图片描述

    抽象工厂模式的主要优缺点:

    1. 抽象工厂模式的主要优点是隔离了具体类的生成,使得客户并不需要知道什么被创建,而且每次可以通过具体工厂类创建一个产品族中的多个对象,增加或者替换产品族比较方便,增加新的具体工厂和产品族很方便;
    2. 主要缺点在于增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。

    抽象工厂模式的主要应用场景

    1. 抽象工厂模式适用情况包括:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节;系统中有多于一个的产品族,而每次只使用其中某一产品族;属于同一个产品族的产品将在一起使用;系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

    4. 原型模式3

    原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。
    在这里插入图片描述

    参考:https://www.cnblogs.com/haizai/p/12404326.html

    浅拷贝的介绍

    1)对于数据类型是基本数据类的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。
    2)对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
    3)前面的克隆羊是浅拷贝
    4)浅拷贝是使用默认的clone()方法来实现
    sheep = (Sheep)supper.clone();

    深拷贝基本介绍

    1)复制对象的所有基本数据类型的成员变量值
    2)为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝
    3)深拷贝实现方式1 :重写clone方法来实现深拷贝
    4)深拷贝实现方式2 :通过对象序列化实现深拷贝

    原型模式的主要应用场景

    大体上有两种使用场景

    1. 在需要一个类的大量对象的时候,使用原型模式是最佳选择,因为原型模式是在内存中对这个对象进行拷贝,要比直接new这个对象性能要好很多,在这种情况下,需要的对象越多,原型模式体现出的优点越明显。

    2. 如果一个对象的初始化需要很多其他对象的数据准备或其他资源的繁琐计算,那么可以使用原型模式。

    3. 当需要一个对象的大量公共信息,少量字段进行个性化设置的时候,也可以使用原型模式拷贝出现有对象的副本进行加工处理。

    注:原型模式的拷贝是从内存(堆内存)中以二进制流的方式进行拷贝,重新分配一个内存块,并不会执行任何构造函数。

    5. 单例模式4

    单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。
    在这里插入图片描述

    单例模式的主要优缺点:

    1. 单例模式的主要优点在于提供了对唯一实例的受控访问并可以节约系统资源;
    2. 其主要缺点在于因为缺少抽象层而难以扩展,且单例类职责过重。

    单例模式的主要应用场景

    1. 系统只需要一个实例对象;客户调用类的单个实例只允许使用一个公共访问点。(一个具有自动编号主键的表可以有多个用户同时使用,但数据库中只能有一个地方分配下一个主键编号,否则会出现主键重复,因此该主键编号生成器必须具备唯一性,可以通过单例模式来实现。)

    结构型模式

    结构型模式(Structural Pattern)描述如何将类或者对 象结合在一起形成更大的结构,就像搭积木,可以通过 简单积木的组合形成复杂的、功能更为强大的结构。

    结构型模式可以分为类结构型模式对象结构型模式

    • 类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。

    • 对象结构型模式关心类与对象的组合,通过关联关系使得在一 个类中定义另一个类的实例对象,然后通过该对象调用其方法。

    根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式

    包含模式

    • 适配器模式(Adapter)

      重要程度:4

    • 桥接模式(Bridge)

      重要程度:3

    • 组合模式(Composite)

      重要程度:4

    • 装饰模式(Decorator)

      重要程度:3

    • 外观模式(Facade)

      重要程度:5

    • 享元模式(Flyweight)

      重要程度:1

    • 代理模式(Proxy)

      重要程度:4

    1. 适配器模式4

    适配器模式(Adapter)的定义如下:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

    在这里插入图片描述

    适配器模式的主要优缺点

    1. 适配器模式的主要优点是将目标类和适配者类解耦,增加了类的透明性和复用性,同时系统的灵活性和扩展性都非常好,更换适配器或者增加新的适配器都非常方便,符合“开闭原则”;
    2. 类适配器模式的缺点是适配器类在很多编程语言中不能同时适配多个适配者类,对象适配器模式的缺点是很难置换适配者类的方法。

    适配器模式的主要应用场景

    1. 适配器模式适用情况包括:系统需要使用现有的类,而这些类的接口不符合系统的需要;想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类一起工作

    实例:

    Sun公司在1996年公开了Java语言的数据库连接工具JDBC,JDBC使得Java语言程序能够与数据库连接,并使用SQL语言来查询和操作数据。JDBC给出一个客户端通用的抽象接口,每一个具体数据库引擎(如SQL Server、Oracle、MySQL等)的JDBC驱动软件都是一个介于JDBC接口和数据库引擎接口之间的适配器软件。抽象的JDBC接口和各个数据库引擎API之间都需要相应的适配器软件,这就是为各个不同数据库引擎准备的驱动程序。

    2. 桥接模式3

    桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

    在这里插入图片描述

    桥接模式的主要优缺点

    1. 桥接模式的主要优点是分离抽象接口及其实现部分,是比多继承方案更好的解决方法,桥接模式还提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,实现细节对客户透明,可以对用户隐藏实现细节;
    2. 其主要缺点是增加系统的理解与设计难度,且识别出系统中两个独立变化的维度并不是一件容易的事情。

    桥接模式的主要应用场景

    1. 需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系;抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响;一个类存在两个独立变化的维度,且这两个维度都需要进行扩展;设计要求需要独立管理抽象化角色和具体化角色;不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统。

    桥接模式实例:

    如果需要开发一个跨平台视频播放器,可以在不同操作系统平台(如Windows、Linux、Unix等)上播放多种格式的视频文件,常见的视频格式包括MPEG、RMVB、AVI、WMV等。现使用桥接模式设计该播放器。

    3. 组合模式4

    组合(Composite)模式的定义:有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。

    组合模式的实现根据所实现的接口的区别分为两种形式,分别称为安全式透明式

    在这里插入图片描述

    组合模式的主要优点有:

    1. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
    2. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;

    组合模式的主要应用场景

    这种组合模式正是应树形结构而生,所以组合模式的使用场景就是出现树形结构的地方。比如:文件目录显示,多及目录呈现等树形结构数据的操作。

    两种实现方式的选择

    **这里所说的安全式组成模式是指:**从客户端使用组成模式上看是否更安全,如果是安全的,那么就不会有发生误操作的可能,能访问的方法都是被支持的。
    **这里所说的透明性组成模式是指:**从客户端使用组成模式上,是否需要区分到底是“树枝对象”还是“树叶对象”。如果是透明的,那就不用区分,对于客户而言,都是Component对象,具体的类型对于客户端而言是透明的,是无需关心的。

    对于组合模式而言,在安全性和透明性上,会更看重透明性,毕竟组合模式的目的是:让客户端不再区分操作的是树枝对象还是树叶对象,而是以一个统一的方式来操作。

    而且对于安全性的实现,需要区分的是树枝对象还是树叶对象。有时候,需要将对象进行类型转换,却发现类型信息丢失了,只好强行转换,这种类型转换必然是不够安全的。

    因此在使用组合模式的时候,建议多采用透明式的实现方式。

    4. 装饰模式3

    装饰(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

    在这里插入图片描述

    装饰模式的主要优缺点

    装饰(Decorator)模式的主要优点有:

    • 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
    • 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。

    其主要缺点是:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。

    装饰模式的主要应用场景

    • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
    • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现。
    • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

    装饰模式的实例

    装饰模式在 Java 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。

    5. 外观模式5

    外观模式的主要优缺点

    外观模式主要优点在于对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易,它实现了子系统与客户之间的松耦合关系,并降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程;

    其缺点在于不能很好地限制客户使用子系统类,而且在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。

    外观模式的主要应用场景

    外观模式适用情况包括:要为一个复杂子系统提供一个简单接口;客户程序与多个子系统之间存在很大的依赖性;在层次化结构中,需要定义系统中每一层的入口,使得层与层之间不直接产生联系。

    外观模式的实例

    6. 享元模式1

    享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。

    • 类图

    在这里插入图片描述

    • 时序图

    在这里插入图片描述

    享元模式的主要优缺点

    享元模式主要优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份;

    其缺点是使得系统更加复杂,并且需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

    享元模式的主要应用场景

    一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;对象的大部分状态都可以外部化,可以将这些外部状态传入对象中;多次重复使用享元对象。

    享元模式的实例:

    享元模式在编辑器软件中大量使用,如在一个文档中多次出现相同的图片,则只需要创建一个图片对象,通过在应用程序中设置该图片出现的位置,可以实现该图片在不同地方多次重复显示。

    7. 代理模式4

    代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。

    代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

    • 代理模式类图:
      在这里插入图片描述
    • 代理模式时序图
      在这里插入图片描述

    代理模式的主要优缺点

    代理模式的主要优点有:

    • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;能够协调调用者和被调用者,在一定程度上降低了系 统的耦合度。
    • 代理对象可以扩展目标对象的功能,也可以控制对真实对象的使用权限;
    • 远程代理使得客户端可以访问在远程机器上的对象,远程机器 可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。;
    • 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系 统资源的消耗,对系统进行优化并提高运行速度。

    其主要缺点是:

    • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
    • 增加了系统的复杂度;

    代理模式的主要应用场景

    • 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。

    • 保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。

    • Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟 到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个 开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。

    • 虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。

    • 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地 的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在 另一台主机中,远程代理又叫做大使(Ambassador)。

    代理模式的实例

    动态代理

    • 动态代理是一种较为高级的代理模式,它的典型应用就是Spring AOP。
    • 在传统的代理模式中,客户端通过Proxy调用RealSubject类的request()方法,同时还在代理类中封装了其他方法(如preRequest()和postRequest()),可以处理一些其他问题。
    • 如果按照这种方法使用代理模式,那么真实主题角色必须是事先已经存在的,并将其作为代理对象的内部成员属性。如果一个真实主题角色必须对应一个代理主题角色,这将导致系统中的类个数急剧增加,因此需要想办法减少系统中类的个数,此外,如何在事先不知道真实主题角色的情况下使用代理主题角色,这都是动态代理需要解决的问题。
    • 动态代理模式的结构图

    行为型模式

    行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。

    行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。

    通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象 之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。

    行为型模式分为类行为型模式和对象行为型模式两种:

    • 类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
    • 对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。根据“合成复用原则”,系统中要尽量使用关联关系来取代继承关系,因此大部分行为型设计模式都属于对象行为型设计模式

    包含模式

    • 职责链模式(Chain of Responsibility)

      重要程度:3

    • 命令模式(Command)

      重要程度:4

    • 解释器模式(Interpreter)

      重要程度:1

    • 迭代器模式(Iterator)

      重要程度:5

    • 中介者模式(Mediator)

      重要程度:2

    • 备忘录模式(Memento)

      重要程度:2

    • 观察者模式(Observer)

      重要程度:5

    • 状态模式(State)

      重要程度:3

    • 策略模式(Strategy)

      重要程度:4

    • 模板方法模式(Template Method)

      重要程度:3

    • 访问者模式(Visitor)

      重要程度:1

    1. 职责链模式3(也叫责任链模式。)

    责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
    类图:
    a

    责任链模式的主要优缺点

    责任链模式是一种对象行为型模式,其主要优点如下。

    1. 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
    2. 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
    3. 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
    4. 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
    5. 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

    其主要缺点如下。

    1. 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
    2. 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
    3. 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

    责任链模式的主要应用场景

    1. 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
    2. 可动态指定一组对象处理请求,或添加新的处理者。
    3. 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。

    责任链模式的实例

    2. 命令模式4

    命令模式(Command Pattern):将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。

    在软件开发系统中,常常出现“方法的请求者”与“方法的实现者”之间存在紧密的耦合关系。这不利于软件功能的扩展与维护。例如,想对行为进行“撤销、重做、记录”等处理都很不方便,因此“如何将方法的请求者与方法的实现者解耦?”变得很重要,命令模式能很好地解决这个问题

    类图:
    在这里插入图片描述

    命令模式主要优缺点

    命令模式的主要优点如下。

    1. 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。
    2. 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。
    3. 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
    4. 方便实现 Undo (撤销)和 Redo(准备) 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。

    其缺点是:可能产生大量具体命令类。因为计对每一个具体操作都需要设计一个具体命令类,这将增加系统的复杂性。

    命令模式的主要应用场景

    命令模式通常适用于以下场景。

    1. 当系统需要将请求调用者与请求接收者解耦时,命令模式使得调用者和接收者不直接交互。
    2. 当系统需要随机请求命令或经常增加或删除命令时,命令模式比较方便实现这些功能。
    3. 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。
    4. 当系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以将命令对象存储起来,采用备忘录模式来实现。

    命令模式的实例

    很多系统都提供了宏命令功能,如UNIX平台下的Shell编程,可以将多条命令封装在一个命令对象中,只需要一条简单的命令即可执行一个命令序列,这也是命令模式的应用实例之一。
    恰饭:
    在这里插入图片描述

    3. 解释器模式1TODO

    4. 迭代器模式5

    迭代器(Iterator)模式的定义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示

    迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现的,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。

    类图:
    在这里插入图片描述

    迭代器模式的主要优缺点

    主要优点如下。

    1. 访问一个聚合对象的内容而无须暴露它的内部表示。
    2. 遍历任务交由迭代器完成,这简化了聚合类。
    3. 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。
    4. 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
    5. 封装性良好,为遍历不同的聚合结构提供一个统一的接口。

    其主要缺点是:增加了类的个数,这在一定程度上增加了系统的复杂性

    迭代器模式的主要应用场景

    1. 当需要为聚合对象提供多种遍历方式时。
    2. 当需要为遍历不同的聚合结构提供一个统一的接口时。
    3. 当访问一个聚合对象的内容而无须暴露其内部细节的表示时。

    由于聚合与迭代器的关系非常密切,所以大多数语言在实现聚合类时都提供了迭代器类,因此大数情况下使用语言中已有的聚合类的迭代器就已经够了。

    迭代器模式的实例

    java中的Iterator

    5. 中介者模式2

    中介者(Mediator)模式的定义:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。

    中介者模式的主要优缺点

    中介者模式是一种对象行为型模式,其主要优点如下。

    1. 降低了对象之间的耦合性,使得对象易于独立地被复用。
    2. 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。

    其主要缺点是:当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护。

    中介者模式的主要应用场景

    • 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时。
    • 当想创建一个运行于多个类之间的对象,又不想生成新的子类时。

    中介者模式的实例

    6. 备忘录模式2

    备忘录(Memento)模式的定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

    类图:
    在这里插入图片描述

    package memento;
    public class MementoPattern
    {
        public static void main(String[] args)
        {
            Originator or=new Originator();
            Caretaker cr=new Caretaker();       
            or.setState("S0"); 
            System.out.println("初始状态:"+or.getState());           
            cr.setMemento(or.createMemento()); //保存状态      
            or.setState("S1"); 
            System.out.println("新的状态:"+or.getState());        
            or.restoreMemento(cr.getMemento()); //恢复状态
            System.out.println("恢复状态:"+or.getState());
        }
    }
    //备忘录
    class Memento
    { 
        private String state; 
        public Memento(String state)
        { 
            this.state=state; 
        }     
        public void setState(String state)
        { 
            this.state=state; 
        }
        public String getState()
        { 
            return state; 
        }
    }
    //发起人
    class Originator
    { 
        private String state;     
        public void setState(String state)
        { 
            this.state=state; 
        }
        public String getState()
        { 
            return state; 
        }
        public Memento createMemento()
        { 
            return new Memento(state); 
        } 
        public void restoreMemento(Memento m)
        { 
            this.setState(m.getState()); 
        } 
    }
    //管理者
    class Caretaker
    { 
        private Memento memento;       
        public void setMemento(Memento m)
        { 
            memento=m; 
        }
        public Memento getMemento()
        { 
            return memento; 
        }
    }
    

    备忘录模式的主要优缺点

    主要优点如下。

    • 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
    • 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
    • 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。

    主要缺点是:资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。

    备忘录模式的主要应用场景

    1. 需要保存与恢复数据的场景,如玩游戏时的中间结果的存档功能。
    2. 需要提供一个可回滚操作的场景,如 Word、记事本、Photoshop,Eclipse 等软件在编辑时按 Ctrl+Z 组合键,还有数据库中事务操作。

    备忘录模式的实例

    7. 观察者模式5

    观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

    类图:
    在这里插入图片描述

    观察者模式的主要优缺点

    观察者模式是一种对象行为型模式,其主要优点如下。

    1. 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
    2. 目标与观察者之间建立了一套触发机制。

    它的主要缺点如下。

    1. 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
    2. 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

    观察者模式的主要应用场景

    通过前面的分析与应用实例可知观察者模式适合以下几种情形。

    1. 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
    2. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

    观察者模式的实例

    在JDK的java.util包中,提供了Observable类以及Observer接口,它们构成了Java语言对观察者模式的支持。

    1. Observable类

    Observable 类是抽象目标类,它有一个 Vector 向量,用于保存所有要通知的观察者对象,下面来介绍它最重要的 3 个方法。

    1. void addObserver(Observer o) 方法:用于将新的观察者对象添加到向量中。
    2. void notifyObservers(Object arg) 方法:调用向量中的所有观察者对象的 update。方法,通知它们数据发生改变。通常越晚加入向量的观察者越先得到通知。
    3. void setChange() 方法:用来设置一个 boolean 类型的内部标志位,注明目标对象发生了变化。当它为真时,notifyObservers() 才会通知观察者。

    2. Observer 接口

    Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 void update(Observable o,Object arg) 方法,进行相应的工作。

    图片引用自:http://c.biancheng.net/view/1390.html

    8. 状态模式3

    状态(State)模式的定义:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

    类图:

    状态模式类图

    状态模式的主要优缺点

    状态模式是一种对象行为型模式,其主要优点如下。

    1. 状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
    2. 减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
    3. 有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
    4. 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。

    状态模式的主要缺点如下:

    1. 状态模式的使用必然会增加系统的类与对象的个数。
    2. 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
    3. 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

    状态模式的主要应用场景

    通常在以下情况下可以考虑使用状态模式。

    • 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
    • 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。

    状态模式的实例

    状态模式在工作流或游戏等类型的软件中得以广泛使用,甚至可以用于这些系统的核心功能设计,如在政府OA办公系统中,一个批文的状态有多种:尚未办理;正在办理;正在批示;正在审核;已经完成等各种状态,而且批文状态不同时对批文的操作也有所差异。使用状态模式可以描述工作流对象(如批文)的状态转换以及不同状态下它所具有的行为。

    9. 策略模式4

    策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

    类图:
    策略模式

    策略模式的主要优缺点

    策略模式的主要优点如下。

    1. 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。
    2. 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
    3. 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
    4. 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
    5. 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。

    其主要缺点如下。

    1. 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
    2. 策略模式造成很多的策略类。

    策略模式的主要应用场景

    策略模式在很多地方用到,如 Java SE 中的容器布局管理就是一个典型的实例,Java SE 中的每个容器都存在多种布局供用户选择。在程序设计中,通常在以下几种情况中使用策略模式较多。

    1. 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
    2. 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
    3. 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
    4. 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构
    5. 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
    6. 如果系统中某个类的对象存在多种状态,不同状态下行为有差异,而且这些状态之间可以发生转换时使用状态模式;如果系统中某个类的某一行为存在多种实现方式,而且这些实现方式可以互换时使用策略模式。

    策略模式的实例

    10. 模板方法模式3

    模板方法(Template Method)模式的定义如下:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。

    类图:
    在这里插入图片描述

    模版方法模式的主要优缺点

    该模式的主要优点如下。

    1. 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
    2. 它在父类中提取了公共的部分代码,便于代码复用。
    3. 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。

    该模式的主要缺点如下。

    1. 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
    2. 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。

    模版方法模式的主要应用场景

    模板方法模式通常适用于以下场景。

    1. 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
    2. 当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
    3. 当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。

    模版方法模式的实例

    11. 访问者模式1TODO

    FAQ

    1. 关于为什么使用工厂模式,而不是直接new

    目前我的理解主要由两点:

    1. 降低代码复杂度:工厂模式下,**不仅仅只有实例化功能,**可以对new的对象进行一些其他操作,比如工厂类创建的圆形,可以添加一些额外的设置,圆的名称,圆的颜色等(这里只是简单举例,有些可能涉及复杂的操作,比如计算设置圆的周长,面积):组合优先于继承相比于继承,我们更优先使用组合——对于组合的好处,可以参考“状态模式(State Pattern)”,一个类可能需要非常多的组件,工厂模式可以降低使用者的代码复杂度和理解难度
    2. 根据DP(迪米特法则)其实调用者并不知道有一个Circle类的存在,他只需要知道这个IShape接口可以计算圆面积,而不需要知道;圆这个类到底是什么类名——他只知道给定一个”circle"字符串的参数,IShape接口可以自动计算圆的面积就可以了!

    2. 抽象工厂模式和工厂模式的区别

    1. 抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。
    展开全文
  • 它们各有各的优缺点。   基于service facade模式,定义了一组业务接口。看起来很简单,事实上很多项目中都是采取这种模式的,传统的web应用中,我们采取分层架构,上层依赖下层提供的接口就是这样一...

    调用业务逻辑的问题,一直有两大派别的做法。一种是基于service facade的设计模式 ,例如EJB的session facade就是属于这种模式。另一种是基于command的设计模式。 它们各有各的优缺点。

     

    基于service facade的模式,定义了一组业务接口。看起来很简单,事实上很多项目中都是采取这种模式的,传统的web应用中,我们采取分层架构,上层依赖下层提供的接口就是这样一种模式。但后来发现一个问题,就是当我们的商业逻辑发生改变的时候,业务接口也会改变,而且业务接口中用到的某个对象改变的时候,也会影响到所有的客户端。当然在比较独立的应用,这个问题基本上不会遇到。

     

    AO模式。这种模式从本质上来讲,是一种command模式,或者称为request-response模式。这样我们可以把业务层做得像web层一样,给一个request就得到一个response。这样client和server端完全是松耦合的。AO/Command/CommandDispatcher等对象的样式,并运用Spring来管理它们。这样做还有一些隐含的好处。因为command是一种通用对象(说白了就是Map),所以在传递业务对象时的同时,我们还可以隐含地传递一些系统变量,例如登录用户、用户IP、访问URL等。无论是远程调用、还是本地调用,甚至是异步调用,都可以得到调用者的一些信息。而所有这一切,都不影响业务逻辑的代码。这为我们debug系统带来了方便。(通过接口调用就很难做到这些)

     

    但是AO模式最严重的问题,就在于command定义的随意性,以及业务接口是弱类型的,无法利用编译器的类型检查,给编程带来麻烦。

     

    为了避免接口变动的问题,我们要求做到商业逻辑改变业务层接口尽可能稳定,尽量将核心业务逻辑放在业务层之后,将用例特定的逻辑放到业务层之外;这要求比较高的业务理解能力和系统分析设计能力,但这样做带来的回报不但是一个稳定的业务层接口,而且是一个稳定的业务层实现。而业务层的变动越小,则系统的正确性、稳定性就越有保障;而且由于业务层只包括核心业务逻辑,因此往往比较精简,易变化的逻辑都放在web层中,提高了整个系统的可理解性和可维护性。要求业务层是稳定的,就像要求数据库表结构具有稳定性一样,这个要求我们觉得并不过分,也是可以做到的,前提是整个团队必须非常关注业务、分析与设计,并有相应的流程和方法学支持。

     

    象如果业务层接口变化了,而客户端还在使用旧的接口调用方式,编译器无法发现这一点,带来的风险是很大的,以前因为这个原因造成不少bug。因此,我们期望如果业务层接口改变了,IDE能够帮我们找到所有客户端的调用之处,方便我们进行统一修改,并且编译器能够帮助我们保证客户端与业务层接口的一致性。在这一点上,service facade模式较command模式优越很多。

     

    service facade模式难以传递调用上下文: 这是可以通过技术手段解决的。可以采用ThreadLocal传递一个称为OperationContext的对象,OperationContext顾名思义就是操作上下文,其中封装了所有由框架提供并由框架使用的调用上下文信息,比如用户主体、角色、环境等等。业务接口不需要关心这些信息,在业务实现中也很少需要使用这些信息,而是由一些框架使用的(如权限、日志等)。当需要远程或异步调用业务接口时,OperationContext也可以通过调用客户端透明传递给远程调用代理,这些在技术上都是没有问题的。

     

    在框架技术选择上,框架技术能够"帮助"或"提示"一个良好的系统设计与实现,但无法"强制"一个良好的设计与实现,因此选择与改进框架技术一定要和建立、统一并推广良好的系统分析与设计方法结合起来,并建立相关的机制来支持和保障,这一块任重道远。

     

    展开全文
  • 外观模式UML图 外观模式UML 定义 外观模式(也成为门面模式)要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。它提供一个高层次的接口,使得子系统更易于使用 类型:结构型模式 使用...
  • 功能 为子系统中的一组接口提供一个一致的界面 解决 主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。 何时使用: 客户端不需要知道系统内部的复杂联系...优缺点 优点: 减少系统相互...
  • 桥接模式(Bridge)是一种结构型设计模式。Bridge模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而...
  • I . 外观模式概念 II . 外观模式 适用场景 III . 外观模式 优缺点 IV . 外观模式与其它设计模式的联系与区别 V . 外观模式 代码示例
  • 【C++设计模式Facade 外观模式详解

    千次阅读 2019-04-29 23:52:53
    外观模式概述 、外观模式结构与实现 、外观模式的适用场景 、外观模式优缺点
  • 一、概述Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用。实际应用中,我们在对付一些老旧的code(尤其是将C的代码转成C++代码)或者即便...
  • 外观(Facade模式优缺点 1. 外观(Facade)模式介绍 定义:是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。 关键代码:在客户端和复杂系统之间再加一层,这一层将调用...
  • Facade(外观)设计模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用。 Facade设计模式概述:  实际应用中,我们在对付一些老旧的code,或者即使不是老旧的...
  • 1、问题场景 场景: 软件系统开发中,可能你定义了一些接口,但是这些接口在不同的模块中实现,客户在使用你的接口时并不知道你的...门面模式定义了一组高层接口,使得一个子系统更加容易使用、 UML图:
  • 1、单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。 2、原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似...
  • 关于设计模式的总结 1.抽象工厂: Factory 提供一个创建一系列或相关依赖对象的接口,而无需指定他们具体的类。针对多级结构. 抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族...
  • [设计模式]Facade外观模式

    千次阅读 2013-01-09 20:14:39
    问题 举一个生活中的小例子,大凡开个学或毕过业的都会体会到这样一种郁闷:你要去n个地方办理n个手续。但是实际上我们需要的就是...Facade模式在高层提供了一个统一的接口,解耦了系统。设计模式中还有另一种模式Media
  • 一、外观模式是什么? 二、外观模式 1.案例 命令模式优缺点 优点 缺点 适配器模式、外观模式以及和装饰者模式的区别
  • 模式优缺点模式不是万金油,不可以滥用模式模式的应用案例:了解它在哪些重要的源码中被使用 该系列会逐步更新于我的博客和公众号(博客见文章底部),也希望各位观众老爷能够关注我...
  • 外观模式Facade

    2017-01-18 13:41:14
    外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高...模式优缺点 优点 1、引入外观模式,是客户对子系统的使用变得简单了,减少
  • 在看了《大话设计模式》一书后,总结了一些笔记,如下: 关于设计模式的总结 1.抽象工厂: Factory 提供一个创建一系列或相关依赖对象的接口,而无需指定他们具体的类。针对多级结构. 抽象工厂模式...
  • 设计模式总结——优缺点

    千次阅读 2018-03-27 11:09:38
    对上一篇的设计模式总结。个人见解不喜勿喷一、策略模式和模板方法模式Strategy模式允许外界使用其接口方法,因而可以将这个接口方法认为是"一整个算法";Template Method模式可以限制所留下的虚方法只对其...
  • 外观模式Facade

    2018-06-28 22:14:18
    2、优缺点:优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。4更好的划分访问层次。缺点:不符合开闭原则,修改相对困难,继承重写都不合适。3、使用场景: 为复杂的模块或子系统提供外界访问的...
  • 文章目录C++设计模式——外观模式(Facade Pattern)目录前言定义定义与特点结构代码示例总结相关设计模式优缺点使用场景参考资料 前言 不得不说,外观模式在开发过程中运用频率非常高,尤其现在各种第三方SDK“充斥”...
  • 外观模式facade

    2011-05-06 14:24:13
    分析将卖cpu等的电子市场视为一个系统,卖各个配件的视为模块,需求就变为:客户需要调用系统的各个模块,A,B,C模块,对于客户如果要知道A,B,C模块功能,并自己组装起来,很麻烦,引入Facade模式,客户无需知道各个...
  • 文章目录概述类型难度定义使用场景UML 类图实例第一步,确定需要调用的子模块第二步,创建外观类第三步,客户端使用技术要点总结优缺点优点缺点总结 概述 Facade Pattern 有时也翻译成面板模式,是一个使用频率极高...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,257
精华内容 1,302
关键字:

facade模式优缺点