设计模式

一、分类

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

二、六大原则 SOLID

1.单一职责原则(Single Responsibility Principle - SRP )

永远不应该有多于一个原因来改变某个类。
对于一个类而言,应该仅有一个引起它变化的原因。说白了就是,不同的类具备不同的职责,各施其责。
应用:当我们做系统设计时,如果发现有一个类拥有了两种的职责,那就问自己一个问题:可以将这个类分成两个类吗?如果真的有必要,那就分吧。千万不要让一个类干的事情太多!

2.开放封闭原则(Open Closed Principle - OCP)

软件实体,如:类、模块与函数,对于扩展应该是开放的,但对于修改应该是封闭的。

当需求有改动,要修改代码了,此时您要做的是,尽量用继承或组合的方式来扩展类的功能,而不是直接修改类的代码。当然,如果能够确保对整体架构不会产生任何影响,那么也没必要搞得那么复杂了,直接改这个类吧。

3.里氏替换原则(Liskov Substitution Principle - LSP)

只要父类能出现的地方子类就能出现。反之,父类则未必能胜任。
在继承类时,务必重写(Override)父类中所有的方法,尤其需要注意父类的 protected 方法(它们往往是让您重写的),子类尽量不要暴露自己的 public 方法供外界调用。

4.最少知识原则(Least Knowledge Principle - LKP)----迪米特法则(Law of Demeter)

类间解耦;
在做系统设计时,不要让一个类依赖于太多的其他类,需尽量减小依赖关系.

5.接口隔离原则(Interface Segregation Principle - ISP)

类间的依赖关系应该建立在最小的接口上;
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。

6.依赖倒置原则(Dependence Inversion Principle - DIP)

高层模块不应该依赖于低层模块,它们应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
赖倒置原则的本质就是通过抽象(接口或抽象类)使个各类或模块的实现彼此独立,互不影响,实现模块间的松耦合。

三、23设计模式

创建型模式

1、简单工厂模式
工厂模式

 

2、抽象工厂模式
涉及到产品族的时候,就需要引入抽象工厂模式;

 

CPU,MainBoard这些构成一个产品族,CPU工厂和MainBoard工厂产出可能因为不兼容不能组装电脑。所以需要抽象的ComputerFactory,再具体实现生产不同的对象;

存在的问题就是若是要再加一个显示器生产,就要给所有的工厂再加上一个产品。有点违反对修改关闭,对扩展开放的原则。

3、单例模式

饿汉模式

public class Singleton {
    // 首先,将 new Singleton() 堵死,private
    private Singleton() {};
    // 创建私有静态实例,意味着这个类第一次使用的时候就会进行创建
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
    // 瞎写一个静态方法。这里想说的是,如果我们只是要调用 Singleton.getDate(...),
    // 本来是不想要生成 Singleton 实例的,不过没办法,已经生成了
    public static Date getDate(String mode) {return new Date();}
}

 

饱汉模式
public class Singleton {
    // 首先,也是先堵死 new Singleton() 这条路
    private Singleton() {}
    // 和饿汉模式相比,这边不需要先实例化出来,注意这里的 volatile,它是必须的
    private static volatile Singleton instance = null;

    public static Singleton getInstance() {
        if (instance == null) {
            // 加锁
            synchronized (Singleton.class) {
                // 这一次判断也是必须的,不然会有并发问题,两个线程可能同时到达这里,产生多个实例
if (instance == null) { instance = new Singleton(); } } } return instance; } }

 嵌套类---推荐

public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

 

4、建造者模式
 XxxBuilder 的类;
Food food = Food.builder().a().b().c().build();这种链式结构;
 lombok的Builder注解可以很好的实现
5、原型模式
一个原型实例,基于这个原型实例产生新的实例,Object 类中有一个 clone() 方法,它用于生成一个新的对象,当然,如果我们要调用这个方法,java 要求我们的类必须先实现 Cloneable 接口,
 
工厂模式在简单工厂模式的基础上增加了选择工厂的维度,需要第一步选择合适的工厂;抽象工厂模式有产品族的概念,如果各个产品是存在兼容性问题的,就要用抽象工厂模式。
单例模式就不说了,为了保证全局使用的是同一对象,一方面是安全性考虑,一方面是为了节省资源;
建造者模式专门对付属性很多的那种类,为了让代码更优美;
原型模式用得最少,了解和 Object 类中的 clone() 方法相关的知识即可。

结构型模式

6、适配器模式

有一个接口需要实现,但是我们现成的对象都不满足,需要加一层适配器来进行适配。

适配器模式总体来说分三种:默认适配器模式、对象适配器模式、类适配器模式。

类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。

对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。

接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

7、装饰器模式

给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,

Decorator类是一个装饰类,可以为Source类动态的添加一些功能,

8、代理模式

代理模式是最常使用的模式之一了,用一个代理来隐藏具体实现类的实现细节,通常还用于在真实的实现的前后添加一部分逻辑。

代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做

9、外观模式

外观模式是为了解决类与类的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口

public class Computer {  
    private CPU cpu;  
    private Memory memory;  
    private Disk disk;  
      
    public Computer(){  
        cpu = new CPU();  
        memory = new Memory();  
        disk = new Disk();  
    }  
      
    public void startup(){  
        System.out.println("start the computer!");  
        cpu.startup();  
        memory.startup();  
        disk.startup();  
        System.out.println("start computer finished!");  
    }  
      
    public void shutdown(){  
        System.out.println("begin to close the computer!");  
        cpu.shutdown();  
        memory.shutdown();  
        disk.shutdown();  
        System.out.println("computer closed!");  
    }  
}

 

10、桥接模式

 

11、组合模式

组合模式用于表示具有层次结构的数据,使得我们对单个对象和组合对象的访问具有一致性。

public class Employee {
   private String name;
   private String dept;
   private int salary;
   private List<Employee> subordinates; // 下属

   public Employee(String name,String dept, int sal) {
      this.name = name;
      this.dept = dept;
      this.salary = sal;
      subordinates = new ArrayList<Employee>();
   }

   public void add(Employee e) {
      subordinates.add(e);
   }

   public void remove(Employee e) {
      subordinates.remove(e);
   }

   public List<Employee> getSubordinates(){
     return subordinates;
   }

   public String toString(){
      return ("Employee :[ Name : " + name + ", dept : " + dept + ", salary :" + salary+" ]");
   }   
}

 

通常,这种类需要定义 add(node)、remove(node)、getChildren() 这些方法。

12、享元模式

享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。

复用对象最简单的方式是,用一个 HashMap 来存放每次新生成的对象。每次需要一个对象的时候,先到 HashMap 中看看有没有,如果没有,再生成新的对象,然后将这个对象放入 HashMap 中。

 

代理模式是做方法增强的,适配器模式是把鸡包装成鸭这种用来适配接口的,桥梁模式做到了很好的解耦,装饰模式从名字上就看得出来,适合于装饰类或者说是增强类的场景,外观/门面模式的优点是客户端不需要关心实例化过程,只要调用需要的方法即可,

组合模式用于描述具有层次结构的数据,享元模式是为了在特定的场景中缓存已经创建的对象,用于提高性能。

行为型模式

13、策略模式

和桥梁模式很像,桥梁模式在左侧加了一层抽象而已。桥梁模式的耦合更低,结构更复杂一些

14、模板方法模式

public abstract class AbstractTemplate {
    // 这就是模板方法
      public void templateMethod(){
        init();
        apply(); // 这个是重点
        end(); // 可以作为钩子方法
    }
    protected void init() {
        System.out.println("init 抽象层已经实现,子类也可以选择覆写");
    }
      // 留给子类实现
    protected abstract void apply();
    protected void end() {
    }
}


public class ConcreteTemplate extends AbstractTemplate {
    public void apply() {
        System.out.println("子类实现抽象方法 apply");
    }
      public void end() {
        System.out.println("我们可以把 method3 当做钩子方法来使用,需要的时候覆写就可以了");
    }
}
public static void main(String[] args) {
    AbstractTemplate t = new ConcreteTemplate();
      // 调用模板方法
      t.templateMethod();
}

 

 

 

15、观察者模式

察者订阅自己关心的主题和主题有数据变化后通知观察者们。

16、迭代子模式

迭代器模式就是顺序访问聚集中的对象,一般来说,集合中非常常见。这句话包含两层意思:一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问。

17、责任链模式

有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求

18、命令模式

司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。

19、备忘录模式

主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C呢,就是一个用来存储备忘录的,且只能存储,不能修改等操作。

20、状态模式

核心思想就是:当对象的状态改变时,同时改变其行为,商品库存中心有个最基本的需求是减库存和补库存。

 

21、访问者模式

访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。

22、中介者模式

中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改。如果使用中介者模式,只需关心和Mediator类的关系,具体类类之间的关系及调度交给Mediator就行,这有点像spring容器的作用。

不同的对象之间有依赖,则引入一个中介类,包含这两个对象,进行关系调度。

23、解释器模式

主要用在OOP开发中的编译器开发中,适用面比较窄,解释器模式用来做各种各样的解释器,如正则表达式等的解释器等等

 

posted on 2018-11-02 14:17  samuel1  阅读(126)  评论(0编辑  收藏  举报

导航