前言

  • 看了很多寓教于学写设计模式的,看的有点头疼,注意力全都在故事上了,满脑子都是鸭子,餐厅之类,还有一堆和设计模式不相关的话,翻书都翻的挺累的。
  • 这里我整理了下23种设计模式,​​没什么多余的话,代码演示,简单粗暴​​,借鉴的地方都附上了参考链接(做个优秀的搬运工),没附上的是自己总结的。
  • 借鉴的例子代码,基本都做了一些精简,​​如果相关例子写的有什么不准确,麻烦在评论里面指出来,最好附上代码,我会尽快修改文章中的相关实例​​。
  • 23种设计模式,一文呈现,方便大家和自己查询,也方便自己随时修改,请配合文章旁边的大纲食用。

总述

7种面向对象设计原则

设计原则名称

定 义

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

一个类只负责一个功能领域中的相应职责

开闭原则(Open-Closed Principle, OCP)

软件实体应对扩展开放,而对修改关闭

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

所有引用基类对象的地方能够透明地使用其子类的对象

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

一个软件实体应当尽可能少地与其他实体发生相互作用

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

使用多个专门的接口,而不使用单一的总接口

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

抽象不应该依赖于细节,细节应该依赖于抽象

合成复用原则(Composite Reuse Principle, CRP)

尽量使用对象组合,而不是继承来达到复用的目的

  • 设计模式可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种
  • 创建型模式主要用于描述如何创建对象(5种)
  • 结构型模式主要用于描述如何实现类或对象的组合(7种)
  • 行为型模式主要用于描述类或对象怎样交互以及怎样分配职责(11种)
  • 图解:花了我蛮多精力画的,有需要到的,可以参照参照
  • 图片是高清图,下载后查看,体验更好

原则简述

1. 单一职责原则

定义:一个类只有一个引起它变化的原因。

理解:对功能进行分类,代码进行解耦,一个类只管一件事

举例:就比如一个网络请求框架大体分为:请求类,缓存类,配置类,不能把这3个混在一起,必须分为3个类去实现不同的功能。

2.开闭原则

定义:一个实体(类、函数、模块等)应该对外扩展开放,对内修改关闭

理解:每次发生变化时,要通过新增代码来增强现有类型的行为,而不是修改原有代码。

举例:就比如在软件的生命周期内,因为产品迭代,软件升级维护等原因,需要对原有代码进行修改时,可能会给原有代码引入错误,也可能使得我们对整个功能不得不进行重构,并且需要对原有代码进行重新测试,这样的话,对开发周期影响很大,所以开闭原则刚好解决这个问题。

3. 里氏替换原则

定义:继承必须确保父类所拥有的性质在子类中仍然成立。

理解:在继承类时,除了扩展一些新的功能之外,尽量不要删除或者修改对父类方法的引用,也尽量不要重写父类的方法。

举例:你看啊,就比如Object有个方法,叫equals,如果不遵守里氏代替原则,它的子类重写了equals这个方法,并且返回了个null,这个子类的下一个继承者也会返回null,那么,在不同开发人员开发时,可能考虑不到这个问题,那么就可能导致程序崩溃。

4.迪米特法则

定义:一个模块或对象应尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立,这样当一个模块修改时,影响的模块就会越少,扩展起来更加容易。

理解:一个对象应该对其他对象有最少的了解;一个类应该对自己需要耦合或调用的类知道得最少,类的内部如何实现、如何复杂都与调用者或者依赖者没关系,调用者或者依赖者只需要知道他需要的方法即可,其他的一概不关心。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。

举例:一般在使用框架的时候,框架的开发者会抽出一个类供外部调用,而这个主要的类像是一个中介一样去调用框架里面的其他类,恰恰框架里面其他类一般都是不可访问(调用)的,这个框架就遵守了迪米特原则,其他开发人员只关心调用的方法,并不需要关心功能具体如何实现。

5.接口隔离原则

定义:使用多个专门功能的接口,而不是使用单一的总接口

理解:在定义接口方法时应该合理化,尽量追求简单最小,避免接口臃肿

举例:在实际开发中,往往为了节省时间,可能会将多个功能的方法抽成一个接口,其实这设计理念不正确的,这样会使接口处于臃肿的状态,这时就需要合理的拆分接口中的方法,另外抽取成一个独立的接口,避免原有的接口臃肿导致代码理解困难。

6.依赖倒置原则

定义:细节应该依赖于抽象,而抽象不应该依赖于细节

理解:高层模块不依赖低层次模块的细节,不依赖具体的类,而是依赖于接口

举例:比如说我们写一个网络框架,为了满足不同开发者的需求,即能使用高效的OkHttp框架,也可以使用原生的API。那么是如何进行切换的呢,这个时候需要面向接口编程思想了,把一些网络请求的方法封装成一个接口,然后分别创建OkHttp和原生API的接口实现类,当然也可以扩展其他网络框架的应用。

7.合成复用原则

定义:尽量使用对象组合,而不是继承来达到复用的目的。

理解:它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

举例:相当于我们开发软件,一个模块的构造,就像搭积木一样,通过组合的形式,完成整体的构建;现在声明式UI框架,对于这种思想比较贯彻。

参考

创建型模式

单例模式

饿汉模式

public class Singleton {
// 只会实例化一次
private static Singleton instance = new Singleton();

// 私有构造方法,防止被实例化
private Singleton() {}

public static Singleton getInstance() {
return instance;
}
}
  • 在未使用该类的时候,也会实例化对象,会造成资源浪费,除非在一定会用到该种类的场景,否则不建议使用。

懒汉模式

public class Singleton {
// 持有私有静态实例,防止被引用;赋值为null,目的是实现延迟加载;volatile修饰是禁止重排
private volatile static Singleton instance = null;

// 私有构造方法,防止被实例化
private Singleton() {}

public static Singleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
  • 使用volatile修饰,可禁止重排,在多线程场景也能保证正常运行;只会在使用的时候,才会去实例化对象,一般场景都可以使用。

静态内部类模式

public class Singleton {
// 私有构造方法,防止被实例化
private Singleton() {}

// 获取实例
public static Singleton getInstance() {
return Inner.instance;
}

// 使用一个内部类来维护单例,只有在该类被加载的时候,才会实例化对象
private static class Inner {
private static Singleton instance = new Singleton();
}
}
  • 饿汉模式升级版,解决了资源浪费问题,同时也能保证线程安全;只有在内部类被加载的时候,才会去实例化对象;相对于懒汉模式,静态内部类的方式避免了排队进同步代码块做null的判断,性能优于懒汉模式,推荐使用。

枚举模式

public enum Singleton {
// 创建一个枚举对象,该对象天生为单例
INSTANCE;
public Singleton getInstance(){
return INSTANCE;
}
}
  • 推荐:effective java中最佳的单例实现模式就是枚举模式,JVM来帮我们保证线程安全和单一实例,在反射和序列化的场景中,仍能保证单一实例。

参考

工厂模式

简单工厂模式

  • 以手机为例来说明
  • 定义一个接口,开机的时候,手机界面上,会显示该手机系统
public interface Phone {
//实施开机操作的时候,返回手机系统
String startUp();
}
  • 实现一个Android手机类,实现Phone接口,返回“Android”手机系统
public class AndroidPhone implements Phone {
@Override
public String startUp() {
return undefinedAndroidundefined;
}
}
  • 实现一个IOS手机类
public class IOSPhone implements Phone {
@Override
public String startUp() {
return undefinedIOSundefined;
}
}
  • 创建手机工厂管理类
public class PhoneFactory {
private static Phone mPhone;

//根据系统关键字获取相应手机对象
public static Phone createPhone(String system) {
switch (system) {
case undefinedAndroidundefined:
mPhone = new AndroidPhone();
break;
case undefinedIOSundefined:
mPhone = new IOSPhone();
break;
}
return mPhone;
}
}
  • 使用
public void test() {
Phone android = PhoneFactory.createPhone(undefinedAndroidundefined);
Phone ios = PhoneFactory.createPhone(undefinedIOSundefined);

System.out.print(android.startUp() + undefined\nundefined);
System.out.print(ios.startUp() + undefined\nundefined);
}
  • 结果显示:Android IOS

工厂模式

  • 工厂模式区别与简单工厂模式的是,工厂模式不是用一个统一的工厂类来管理所有对象,而是每一个对象都有不同的工厂相对应。
  • 继续以手机为例说明,需要针对Android和IOS手机这俩个实现类,去构建不同的工厂,这边用接口去规范不同的工厂类
  • 手机工厂接口
public interface PhoneFactory {
//获取相关手机实例
Phone getPhone();
}
  • 创建Android手机工厂
public class AndroidPhoneFactory implements PhoneFactory {
@Override
public Phone getPhone() {
return new AndroidPhone();
}
}
  • 创建IOS手机工厂
public class IOSPhoneFactory implements PhoneFactory {
@Override
public Phone getPhone() {
return new IOSPhone();
}
}
  • 使用
public void test() {
PhoneFactory androidMiFactory = new AndroidPhoneFactory();
PhoneFactory iosFactory = new IOSPhoneFactory();

System.out.print( 版权声明:本文来源51CTO,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.51cto.com/u_13689323/4920209
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2023-01-01 14:17:21
  • 阅读 ( 291 )
  • 分类:设计模式

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢