Java 设计模式学习笔记(7月15号)

作者信息

作者:黄钰朝
邮箱:kobe524348@gmail.com
日期:2019年7月15日

前言

今天的学习任务是设计模式。主要学习设计模式的6大原则,还有学习安排上提到的三种设计模式:单例模式,工厂模式,观察者模式。

一.六大设计原则

1.1 开闭原则(Open Close Principle,OCP)

一句话:“对扩展开放,对修改关闭”

也就是想对类进行改动时不要直接修改写好的代码,而是应该在原来的基础上新建一个类,然后用新的类整个替换掉之前 的,具体在项目中可以通过继承原来的类,也可以通过实现该类的接口(如果该类有接口的话)来实现,这样做的好处在于,避免在修改之前的类时出现问题,并且一旦新的类运行时出现问题,还可以及时回退到原来的类。而且,使用了原来的类的项目可以选择跟随,也可以停留在之前的类继续使用。

1.2 单一职责原则(Single Responsibility Principle,SRP)

官方定义:一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分(There should never be more than one reason for a class to change)

其实就是,一个类应该只干一类事。原因很简单,如果一个类干的事情太多,类本身就变得复杂,难以维护(别人看不懂),并且因为很多功能放在一起,形成绑定,耦合度就高了。

但是,什么叫”一类事“?根据《设计模式之禅》作者的说法:看着办。分类分得太细,项目开发效率就上不去,分得粗糙,解耦的效果又不明星。所以,根据经验自己权衡。

1.3 里氏代换原则(Liskov Substitution Principle,LSP)

官方说法:Functions that use pointers or references to base classes must be able to useobjects of derived classes without knowing it.所有引用基类的地方必须能透明地使用其子类的对象。

这原则主要是为了实现:父类出现的地方,都可以把父类替换成子类,而不会产生错误或异常。

根据Java中继承和多态的知识,可以知道父类换成子类基本没有语法上的问题,主要是不要产生错误,核心的方法就是,子类不要修改或者覆盖父类的方法,具体做法是:

  • 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法

为什么必须实现父类的抽象方法?因为如果没有全部实现抽象方法,那么这个子类就也是一个抽象类,也就无法被实例化,直接不符合上述官方说法中"使用其子类的对象",因为连对象都没有。

为什么不能重写父类的非抽象方法,很简单,因为父类的非抽象方法是已经写好的具体方法,覆盖重写时,可能导致出现不兼容。

  • 子类中可以增加自己特有的方法

当然可以增加特有方法,因为使用父类引用的地方永远不会使用到子类特有的方法。因此原来父类的功能不会被影响。

  • 当子类重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松

注意这里是“重载”,因为子类继承了父类的方法,然后再去重载这个方法,而重载方法是根据参数的不同来区分的,如果,子类的方法输入参数更严格,则某些情况下,会导致子类方法覆盖父类方法,比如下面这种

假设父类中有一个方法:
void method(Object obj){
	System.out.println("obj");
}

子类中继承上面的方法之外,还有一个方法:
void method(String str){
    System.out.println("str");
}
父类参数是Object,子类参数是String,这就是子类参数比父类参数更严格的情况
那么,如果在子类调用这个方法,传入的参数为String类型时,会调用子类的method的方法
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格

这个原因也很简单了,如果子类对象的返回值更宽松的话,接收返回值的时候可能出现问题。

1.4 依赖倒置原则(Dependence Inversion Principle,DIP)

定义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions)。

核心思想:要面向接口编程,不要面向实现编程。接口就是各个模块的抽象。

1.5 接口隔离原则(Interface Segregation Principle,ISP)

罗伯特·C.马丁的定义:客户端不应该被迫依赖于它不使用的方法(Clients should not be forced to depend on methods they do not use)。

其他定义:一个类对另一个类的依赖应该建立在最小的接口上(The dependency of one class to another one should depend on the smallest possible interface)。

也就是拆分大接口,变成小接口,以便使用接口时不要带上一些不必要的方法。可以看成接口的单一职责原则。

1.6 迪米特法则(Law of Demeter,LoD)

也叫做:最少知识原则(Least Knowledge Principle,LKP)

定义:只与你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to strangers)。

一个类的“直接朋友”就是成员变量,方法的参数和返回值,而不包括方法中的局部变量。

一个类在方法中和其他没有在成员变量,方法参数中定义的类产生联系,就属于"和陌生人说话"。

按照迪米特法则,就是要进行类间解耦。具体的做法是:

  • 类的方法中尽量不要引入本类中没有的类的对象
  • 只在必须的时候使用public关键字

PS:迪米特法则的精确内涵我暂时存疑,还是觉得没有完全掌握这个原则的真实含义和好处

二.单例模式(Singleton)

2.1 定义

指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

也就是一个类的对象同一时间在系统中只有一个。

2.2 使用场景

  • 没有状态的类,这些类没有成员变量,只是一些方法的合集,没有创建多个对象的需要。
  • 全局性的类,这些类用来保存提供给全局访问的信息,比如配置信息,数据库连接池,工厂

2.3 优缺点

优点:

  • 减少创建对象,节省系统资源。
  • 保证某些数据全局唯一

缺点:

  • 创建的单例对象长时间不使用,可能会被系统回收,导致数据丢失

2.4 饿汉式单例和懒汉式单例

  • 饿汉式:单例对象在类加载时立即被创建
  • 懒汉式:单例对象在使用时(调用getInstance方法时)才被创建

2.5 懒汉式的线程安全问题

懒汉式单例在多线程环境下存在线程安全问题

主要问题在于getInstance方法被多个线程并发访问时可能会导致其中创建对象的操作多次被执行

原因是:getInstance方法判断单例没有被创建时,会创建一个单例对象。假设A线程判断单例没有被创建,那么接下来它会准备创建一个对象,此时在A还没有创建对象之前B线程也判断单例没有被创建,那么B也准备创建一个对象,这样的最终结果就是单例对象被重复创建了。

三.工厂模式(Factory Method)

PS:设计模式只有一天的时间学习,这里写得很简略

3.1 定义

工厂模式就是把依赖对象的创建交给一个第三方类来执行,这个第三方类就是“工厂”,被创建的对象就是“产品”

工厂模式可分为:简单工厂和抽象工厂

抽象工厂就是“工厂的工厂”,让多个工厂实现同一个抽象的工厂接口,然后用一个工厂来生产这些不同的工厂。

3.2 使用场景

  • 需要经常变更的类,将这些类的创建过程放在工厂中,获取对象时使用接口去接收,这样将来不管工厂中对象的生产过程如何改动,只要还是这个接口的实现类,这里的代码就不用改动。

3.3 优缺点

优点:

  • 使用类的对象时可以不用关心对象的创建过程
  • 容易替换,只需要修改工厂中生产过程,即可使所有使用工厂获取对象的地方得到修改后的类的对象

缺点:

  • 实现方式比直接new一个对象复杂

很显然是利大于弊。

四.观察者模式 (Observer Pattern)

4.1 定义

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

其实就是在对象状态改变的时候去调用某个被事先指定的方法,当然调用的过程会有多层封装实现解耦。

4.2 使用场景

多了去了,需要事件监听的地方都可以用。

4.3 优缺点

优点:

  • 建立观察者和被观察者之间的触发机制
  • 降低观察者和被观察者的耦合关系

缺点:

  • 观察者过多时,发布通知需要的时间长,影响程序执行效率
  • 观察者和被观察者的耦合关系不能完全解除,可能出现循环引用

总结

学设计模式的时间太短了,主要的时间都花在研究6大原则的真正内涵上,最后到具体的设计模式上的时间不多,不过设计模式是脱不开项目实践的,这些知识还是等到项目中再去思考和实践,慢慢摸索和总结,才有可能真正领悟其中的内涵。

参考资料

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值