记得点击 “欢少的成长之路“, 设为星标⭐
后台点击【联系我】,申请加入优质技术学习社群
大家好,我是Leo。
之前聊过了 MySQL 、Redis、RocketMQ、秒杀系统、计算机网络
由于现阶段工作规划的问题,计算机网络暂时放放,先聊一下设计模式。
七大原则
单一职责原则
对类来说,即一个 类应该只负责一项职责,如类A负责两个不同的职责,我们把职责分为职责1和职责2。当职责1需要变更的时候,我们修改的类A,可能会造成职责2执行错误。
真实场景:货主端的新增司机就应该只是新增司机,即使从类上做不到单一,最起码的底线是要做到方法上的单一。即使当下没有这个需求也不可以。也要考虑扩展性,可读性!
为我们解决了什么
-
降低类的复杂度,一个类只负责一项职责 -
提高类的可读性,可维护性 -
降低变更引起的风险 -
通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级违反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责原则
接口隔离原则
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。
用不到的接口不要实现,可以用抽象解决这一问题。或者定义多个接口解决这一问题
为我们解决了什么
-
单一化接口的职责,从而有效地避免接口污染。 -
当一个接口的方法过多,往往会造成使用该接口的类中闲置一些方法,造成代码的冗余,通过细分接口可有效避免该现象。 -
可以提高代码的灵活性,就好比搭积木一样,我们可以将一个大的接口拆成多个小接口,不同的小接口可以有多种组合。 -
促使程序高内聚、低耦合。
依赖倒转原则
-
高层模块不应该依赖低层模块,二者都应该依赖其抽象 -
抽象不应该依赖细节,细节应该依赖抽象 -
依赖倒转的中心思想是面向接口编程 -
依赖倒转原则是基于这样的设计理念;相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在Java中,抽象指的是接口或抽象类,细节就是具体的实现类 -
使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
为我们解决了什么
-
可以减少类间的耦合性、提高系统稳定性,提高代码可读性和可维护性,可降低修改程序所造成的风险。
里氏替换原则
在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法。继承实际上是让两个类的耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖来解决问题(基类)
为我们解决了什么
-
代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性; -
提高代码的重用性; -
子类可以形似父类,但又异于父类,“龙生龙,凤生凤,老鼠生来会打洞”是说子拥有父的“种”,“世界上没有两片完全相同的叶子”是指明子与父的不同; -
提高代码的可扩展性,实现父类的方法就可以“为所欲为”了,君不见很多开源框架的扩展接口都是通过继承父类来完成的; -
提高产品或项目的开放性。
需要我们注意什么
-
继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法; -
降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束; -
增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的结果————大段的代码需要重构。
开闭原则
-
一个软件实体如类,模块,函数应该对扩展开放,对修改关闭。用抽象构建框架,对实现扩展细节。 -
当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。 -
编程中遵循其他原则以及使用设计模式的目的就是遵循开闭原则
迪米特法则
-
一个对象应该对其他对象保持最少的了解(最少知道原则) -
类与类关系越密切,耦合度越大 -
对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public方法,不对外泄露任何信息 -
只与直接的朋友通信(B类的调用,局部变量B只能算间接朋友)
局部变量不应该出现
合成复用原则
一个类使用另一个类的代码,尽量不使用继承,而是合成
可以通过传递类或者set类的方式,通过这个类名调用,而不是继承
设计模式
设计模式类型
创建型模式
单例模式,抽象工厂模式,原型模式,建造者模式,工厂模式
结构型模式
适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式
行为型模式
模板方法模块,命令模式,访问者模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,职责链模式(责任链模式)
单例模式
-
单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能 -
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
方式
-
饿汉式(静态常量) -
饿汉式(静态代码块) -
懒汉式(线程不安全) -
懒汉式(线程安全,同步方法) -
懒汉式(线程安全,同步代码块) -
双重检查 -
静态内部类 -
枚举
应用场景
-
需要频繁创建和销毁的对象 -
创建对象时耗时过多或耗费资源过多,但又经常用到的对象,工具类对象,频繁范围数据库或文件的对象
饿汉式(静态常量)
public static void main(String[] args){
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2)
}
class Singleton{
private Singleton(){}
private final static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
优点
-
写法简单,类装载时完成实例化,避免线程同步问题
缺点
-
在类装载的时候完成了实例化,没有达到Lazy Loading的效果,如果从始至终从未使用过这个实例,则会造成内部的浪费
结论
-
饿汉式(静态常量)可以使用,可能会造成内存浪费
饿汉式(静态代码块)与饿汉式(静态常量) 类型
懒汉式(线程不安全)
public static void main(String[] args){
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2)
}
class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
优点
-
起到了Lazy Loading的效果,但是只能在单线程下使用
缺点
-
存在系统安全性问题,并发情况下,容易创建多个实例
结论
-
在单线程可以使用,多线程不能使用
懒汉式(线程安全)
public static void main(String[] args){
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2)
}
class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
优点
-
解决了线程不安全问题
缺点
-
效率太低了,每个线程在想获得类的实例时候,执行getInstance方法都要进行同步,而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低
结论
-
在实际开发中,不推荐使用这种方式
懒汉式(线程安全,双重检查)
public static void main(String[] args){
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2)
}
class Singleton{
private static volatile Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
优点
-
线程安全,延迟加载,效率高
结论
-
在实际开发中,推荐使用这种单例模式
静态内部类方式创建
public static void main(String[] args){
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2)
}
class Singleton{
private static volatile Singleton instance;
private Singleton(){}
private static class SingletonInstance{
private static final Singleton INSTANCE = new Singleton();
}
public static synchronized Singleton getInstance(){
return SingletonInstance.INSTANCE;
}
}
-
这种方式采用了类装载机制来保证初始化实例时只有一个线程 -
被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化 -
类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮我们保证了线程的安全性,在类初始化时,别的线程是无法进入的。
优点
-
避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
结论
-
推荐使用
枚举方式创建
public static void main(String[] args){
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2)
}
enum Singleton{
INSTANCE;
public void sayOk(){
System.out.println("sayOk");
}
}
优点
-
通过借助jdk1.5中添加的枚举实现单例模式,不仅能避免多线程同步问题,而且还能防止发序列化重新创建新的对象
结论 :推荐使用
总结
了解设计模式的七大原则,首先介绍了23种设计模式的的单例模式,从众多单例模式的写法中推荐使用 懒汉式(线程安全,双重检查),静态内部类方式,枚举方式创建。不仅保证系统安全问题,还能解决无效占用内存。
下一篇聊聊设计模式中的工厂模式,工厂模式分两种:抽象工厂模式 和 简单工厂模式
原文始发于微信公众号(欢少的成长之路):3万字聊聊设计模式(一)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/60548.html