• 设计模式之禅(2)-设计模式


    • 单例模式:


    一个类在系统中有且只能有一个对象。这个模式在spring中很常见。

    UML类图:

    代码:

    上面的代码也成为饿汉模式,不管有没有用到,先实例化。还有一种是懒汉模式,代码如下

    这里加了个判断,但是这里的代码会有线程安全的问题。需要加锁。

     工厂模式


    定义一个用于创建对象的接口,让子类决定实例化那个类,使一个类的实例化延迟到其子类。

    UML类图:

    代码:

     我们看8-10的抽象工厂类,在接口中定义了实例化的对象为Product的子类,以后无论增加多少产品,只要是Product的子类,都能通过这个工厂类来实例化对象。这种高层模块依赖抽象的设计模式,正是里式替换法则所要求的。

    我们看下具体的场景类

     具体实例化哪个在场景类中定义。

    抽象工厂模式


     工厂模式的扩展

    我们直接看源码UML:

    代码:

     

       这里其实能看出来一个问题了,如果我再加一个产品C,有哪几个类需要改动呢。AbstracCreator需要添加创建产品C的方法,两个工厂实现类同样都需要实现。这样的代码不能拥抱变化,问题太大。其实上述类图可以再抽象一层出来做优化,但是仔细一想,改动后就不是抽象工厂模式了。

     模板方法模式


     定义一个操作的顺序,操作中具体的原子步骤在子类中实现,使得子类不改变一个操作的步骤即可重新定义某些特定的步骤

     UML类图:

    代码:

    模板方法时Java继承的提现,使用还是很简单的。 扩展的时候可以衍生一个钩子方法,具体不仔细描述。

     

    建造者模式


    变化是永恒的,你永远无法猜到下一秒产品经理在想什么。建造者模式定义一个复杂对象的构建与他的表示分离。

    UML类图:

    代码:

     我们看抽象建造者,setpart里可以定义不同的方法顺序,每一个产品的顺序都可以不同。buildProduct只是返回一个对象。产品的构建和表示在这里分离了。实际项目中Product最好能抽象出来

    代理模式


    为其他对象提供一种代理以控制对这个对象的访问

    UML类图:

    代码:

    通过构造函数把需要代理的类传进来,即可实现代理。

    上述代理只是一种设计模式,正式项目中我们一般会参照这种模式,用动态代理来实现。

    原型模式


     通过原型实例指定创建对象的种类,并且通过拷贝这些原型创建出新的对象

    UML类图:

      代码:

    原型模式有几个注意点

    1.克隆的时候不会执行构造函数

    2.注意浅拷贝和深拷贝的区别

    中介者模式


    用一个中介者封装一系列的对象交互,中介者使各对象不需要显示的相互作用,从而使其耦合松散,而且可以独立的改变他们的交互。

    UML类图:

     代码:

    中介者模式可以减少类之间的依赖,但是随之带来的是中介者这个类会变得很大。

    命令模式


     将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

    代码:

    命令模式是比较常用的模式,对不同的请求抽象出相同的抽象响应,并对抽象做出具体的定义。这种思想在项目中尤为常见。

    责任链模式


    使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,知道有对象处理它为止。

    UML类图:

    代码:

    责任链模式屏蔽了请求的处理过程,你只需要把请求发送给第一个处理者,接下的过程就无需关心了。

    装饰模式


     动态给一个对象添加一些额外的职责。

    UML类图:

    这次直接看场景类,大概就知道怎么玩了。

    装饰模式可以动态的扩展类的功能。但是多层扩展比较复杂,不推荐。

    策略模式


     定义一组算法,将每个算法分装起来,并且使他们之间可以相互转换。

     策略模式是抽象封装的最基本表现。但是会有个问题,使用该策略之前必须要先知道这个策略的具体含义,这有点不符合迪米特法则。

    适配器模式


     将一个类接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

     UML类图:

    代码:

     

    上述代码就是适配器模式的简单示例,上述模式只是类级别的适配器模式,由于Java是单继承的,如果适配器想适配好几个实例,上述模式就要改造下。

    这次不继承了,改用关联了。通过构造函数关联进来。大体上就是这么玩的。

    迭代器模式


    他提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。

     UML类图:

    代码:

    有没有觉得迭代器模式很眼熟,java所有的集合类都运用了迭代器模式,甚至已经成为一个最基本的工具。所以如果要用迭代器那就直接使用Java提供的Iterator。千万别自己写一个。

    组合模式 


     将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

    UML类图:

    代码:

    组合模式通常用于树形结构,这种思想结合数据库表,使得代码层级清晰明了。

    观察者模式


    定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

    UML类图:

    代码:

    这个模式平时很熟悉,大多数消息服务就是这种模式的体现。观察者和被观察者的扩展也很容易,但是要注意的是,观察者和被观察者可以链式的传播下去,这样的代码比较脆弱。

    门面模式


     要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,是的子系统更易于使用。

    UML类图:

    代码:

    门面模式的代码很简单,重要的是门面模式的设计思路。在现在微服务提倡的时代。通过门面模式封装多个系统的请求,对外只暴露我们想暴露的服务。

      

     备忘录模式


    在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。 

     UML类图:

    上述代码只是单状态的记录 ,大多数我们需要保存多个状态可以用到Map。备忘录的建立就是为了使用,所以一旦建立了备忘录,请尽早使用。不使用了尽早gc掉。

    访问者模式


     封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

    这个模式有点复杂。先用个小demo介绍下

    class Element{
        public void methodA(){
             System.out.println("我是Element");  
        }
    
        public void method2(Visitor visitor){
            visitor.show(this);  
        }
    }
    
    class Visitor{
        public void showA(Element element){
            element.methodA();
        }
    }

    场景类:

    public class Test {  
        public static void main(String[] args){  
            Element element = new Element();  
            element.method1();  
            element.method2(new Visitor());  
        }  
    }
    

     输出:

    我是Element

    我是Element

     上述就是访问者模式的小demo。

    下面看类图:

    代码:

    Element负责数据的加载,Visitor负责数据的展现。如果现在要再添加一种数据,只需要增加一个Element子类,在Visitor下添加一个新的方法即可。

     访问者模式的缺点:

    Element类的细节需要暴露给Visitor,Element的变化会导致Visitor的变化。

    状态模式


    当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

    UML类图:

    代码:

    上述代码我们只看到行为的变化,隐藏了状态的变化。对外部来说,只需关注行为即可。

    优点:结构清晰,封装性好

    缺点:子类会膨胀。 

     解释器模式


     给定一门语言,定义它的文法的一种表示。并定义一个解释器,该解释器使用该表示来解释语言中的橘色。

    UML类图:

    代码:

    这个模式从未见过。

    解释器模式使用了大量的循环递归,性能上会是一个很大的问题。通常我们会用脚本语言去代替解释器模式。

    享元模式


    使用共享对象可以有效的支持大量的细粒度的对象

    UML类图:

    代码:

    我们直接看享元工厂

     

    享元模式有个问题,多线程模式下会有线程安全问题。使用时一定得注意

    桥梁模式


     将抽象和实现解耦,使得两者可以独立变化

    代码:

     桥梁模式也是是基本的抽象继承实现,当你不希望出现太多继承的时候,可以考虑用桥梁模式。

    后续


       23个设计模式花了几天全部写完了,乘着这次机会,又重新回顾了一遍设计模式。感觉收获很大。有很多人会觉得设计模式不重要,但是最近在做设计的时候,发现不自觉的会运用起一些设计模式。之前的设计想到哪里设计到哪,完全凭借着经验和感觉。但现在的设计,比以前多了份思考,心里开始有了一份标准。抽象业务系统,控制系统复杂度。希望将来的每一行代码都能是一个好的设计。

     转载请标注来源:http://www.cnblogs.com/xmzJava/p/9015780.html

  • 相关阅读:
    Matlab矩阵操作函数的使用(reshape,imresize,remat,permute)
    归一化数据的好处
    博客园中用markdown编辑器编辑带下标的符号
    反向传播
    稀疏表示和字典学习
    先验概率和后验概率
    Local Generic Representation for Face Recognition with Single Sample per Person (ACCV, 2014)
    删除数组
    数组扩容(指定位置)+插入最后
    创建数组的几种方式,遍历+泛型合并
  • 原文地址:https://www.cnblogs.com/xmzJava/p/9015780.html
Copyright © 2020-2023  润新知