设计模式学习笔记

软件中既有变化的部分又有稳定的部分,设计模式总结了几种抽象出稳定部分的方式,让我们能通过设计模式尽量使代码符合设计模式原则(开闭原则、单一职责原则、依赖倒置原则、里氏替换原则、接口隔离原则)

设计模式分类

创建型:抽象和封装对象创建过程,客户程序不再关注对象的具体创建,只需要去使用这些创造好的对象。包括:抽象工厂模式、工厂方法模式、单例模式、创建者模式、原型模式。
结构型:怎么样组装现有的类,设计他们的交互模式,以便达到某种功能。包括:适配器模式、桥接模式、组合模式、装饰模式、门面模式、享元模式、代理模式。
行为型:涉及到算法和类的职责分配,描述了对象和类之前的通信模式并且刻画了程序运行时难以跟踪的复杂控制流。包括:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、状态模式、策略模式、模板方法模式、观察者模式、访问者模式。

设计模式原则

单一职责原则

一个类或模块只负责一个职责,不要承担过多任务。原则上我们在设计类的时候不要设计大而全的类,要设计功能单一的类。实际开发时不必严格遵守,等业务发展到一定程度再进行拆分
什么时候需要重构或者设计
1、类依赖过多其他类
2、类提供的功能与其名字不想匹配
3、类的代码函数过多

开闭原则

多扩展开放,对修改关闭。添加一个功能应该是在已有代码基础上进行扩展,而不是修改已有的代码。
开闭原则需要我们在设计代码时预留扩展点,而扩展点的考虑需要结合业务以及用户使用方式、版本升级等等。当然如果为了预留扩展点导致代码开发难度大大提高,这也得不偿失,因此也需要我们进行权衡。

里氏替换原则

子类能够替换程序中父类对象出现的任何地方,并且保证原来的程序的逻辑行为不变以及正确性不会被破坏

接口隔离原则

客户端不应该依赖它不需要的接口。(和单一职责有点类似,但这个是接口层面)

依赖倒置原则

高层模块(调用者)不要依赖底层模块(被调用者),高层模块和底层模块应该通过抽象来相互依赖。抽象不要依赖具体实现细节,具体实现细节依赖抽象。如Spring框架中的Aware接口,框架依赖Aware接口给予具体的视线增加功能,但是通过接口来获取功能,而不是直接耦合实现。

设计模式详解

这里说明的设计模式并非全部23种设计模式

image.png

创建型

单例模式

定义

保持一个类只有一个实例,并且提供一个全局访问点

应用场景

spring的单例模式、线程池、数据库连接池

创建方法

只列举了部分

懒汉模式

双重检查加锁

class LazySingleton {
    //volatile防止指令重排
    private static volatile LazySingleton lazySingleton;
    //无法防止反射攻击
    private LazySingleton(){

    }

    public static LazySingleton getInstance() {
        if (lazySingleton == null) {
            synchronized (LazySingleton.class) {
                if (lazySingleton == null) {
                    lazySingleton = new LazySingleton();
                }
            }
        }
        return lazySingleton;
    }
}
饿汉模式
class HungrySingleton{
    //通过JVM类加载来保证单例以及线程安全,在初始化阶段给类的静态变量赋值
    private static HungrySingleton instance = new HungrySingleton();
    private HungrySingleton(){
        //防止反射攻击
        if (instance != null) {
            throw new RuntimeException("单例不允许多个实例");
        }
    }

    public static HungrySingleton getInstance() {
        return instance;
    }
}
测试
public class SingletonDemo {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 20; i++) {
            System.out.println(LazySingleton.getInstance());
        }
    }

}

应用场景

线程池、数据库连接池、spring单例模式

优点

工厂方法模式

定义

定义了一个用于创建对象的接口,让子类决定实例化哪个类,将创建对象延迟到子类

创建方法

package edu.wyn.designpattern;


abstract class Application {
    abstract Product createObject();

    Product getObject() {
        return createObject();
    }
}

class ConcreteProductA extends Application {
    @Override
    Product createObject() {
        return new ProductA();
    }
}

class ConcreteProductB extends Application {
    @Override
    Product createObject() {
        return new ProductB();
    }
}

interface Product {
    void printName();
}

class ProductA implements Product {

    @Override
    public void printName() {
        System.out.println("this is product a");
    }
}

class ProductB implements Product {

    @Override
    public void printName() {
        System.out.println("this is product b");
    }
}
public class FactoryMethodDemo {

    public static void main(String[] args) {
        Application application = new ConcreteProductA();
        application.createObject().printName();

        Application application2 = new ConcreteProductB();
        application2.createObject().printName();
    }
}

应用场景

1、不知道使用对象的确切类型
2、希望为库或者框架提供扩展其内部组件方法时

优点

1、将具体产品和创建者解耦
2、符合单一职责原则
3、符合开闭原则

抽象工厂模式

定义

提供一个创建一系列相关或互相依赖对象的接口,而无需指定他们具体的类

创建方法

package edu.wyn.designpattern;

public class AbstractFactoryDemo {

    public static void main(String[] args) {
        IDatabaseUtils iDatabaseUtils = new MysqlDataBaseUtils();
        IConnection connection = iDatabaseUtils.getConnection();
        connection.connect();
        ICommand command = iDatabaseUtils.getCommand();
        command.command();
    }
}

interface IConnection{
    void connect();
}

class MysqlConnection implements IConnection {

    @Override
    public void connect() {
        System.out.println("mysql connection...");
    }
}

interface ICommand{
    void command();
}

class MysqlCommand implements ICommand {

    @Override
    public void command() {
        System.out.println("mysql command...");
    }
}

interface IDatabaseUtils{
    IConnection getConnection();
    ICommand getCommand();
}

class MysqlDataBaseUtils implements IDatabaseUtils {

    @Override
    public IConnection getConnection() {
        return new MysqlConnection();
    }

    @Override
    public ICommand getCommand() {
        return new MysqlCommand();
    }
}

应用场景

程序需要处理不同系列的相关产品,但是我们不希望它依赖于这些产品的具体类的时候,可以使用抽象工厂

优点

1、可以确定从工厂中得到的产品是彼此兼容的
2、可以避免具体产品和客户端代码之间的紧密耦合
3、符合单一职责原则
4、符合开闭原则

与工厂方法的区别

相当于将一组相关的application(工厂方法)放在了一个接口中

建造者模式

定义

将一个复杂对象的创建和它的表示分离,使得同样的创建过程可以创建不同的表示

创建方法

lombok的builder

应用场景

1、需要生成的对象具有复杂的内部结构
2、需要生成的对象内部属性本身相互依赖
3、与不可变对象配合使用

优点

1、建造者独立,易扩展
2、便于控制细节风险

原型模式

定义

创建对象的种类,然后通过拷贝这些原型创建新的对象

创建方法

实现Cloneable接口并且重写clone方法,要注意引用类型是浅拷贝,要让引用类型也实现Cloneable

应用场景

代码不需要依赖于需要复制的具体类

优点

1、不耦合具体类的情况下克隆对象
2、避免重复的初始化代码
3、更方便构造复杂对象

结构型

适配器模式

定义

将类的接口转换为客户端希望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作

创建方法

对象适配器--组合
类--继承

应用场景

1、希望使用某些现有类,但其接口与我们其他代码不兼容
2、当你希望重用几个现有的类,但这些类缺少一些不能添加到超类中的公共功能时

优点

1、符合单一职责原则
2、符合开闭原则

装饰模式

定义

在不改变原有对象的基础上,将功能附加到对象上

创建方法

应用场景

扩展一个类的功能,或者给一个类添加附加职责

优点

1、不改变原有对象的情况下给一个对象扩展功能
2、使用不同的组合可以实现不同的效果
3、符合开闭原则

享元模式

定义

运用共享技术有效支持大量细粒度对象

优点

若系统有大量类似对象,可以节省大量的内存和CPU,比如字符串常量池

门面模式

定义

为子系统中的一组接口提供一个一致的接口,门面模式定义了一个高层接口,这个接口使得这一子系统更容易使用

应用场景

1、需要使用复杂子系统有限但直接的接口
2、想要将子系统组织成层
3、微服务时对外提供的接口

优点

简化客户端调用

行为型

责任链模式

定义

为请求创建了一个接收者对象的链

应用场景

对输入对象需要进行多种校验

优点

1、请求的发送者和接收者解耦
2、可以控制执行顺序
3、符合开闭原则和单一职责原则

策略模式

定义

定义了算法族,分别封装起来,让它们之间可以互相替换,此模式的变化独立于算法的使用者

应用场景

优点

1、符合开闭原则
2、符合单一职责原则

模板方法模式

定义

定义了一个操作的算法骨架,而将一些步骤延迟到子类中。子类在不改变整个算法框架的基础上可以重定义算法的某些特定步骤

创建方法

继承、多态

应用场景

spring中扫描bean的方法

优点

1、符合开闭原则

观察者模式

定义

定义了对象之间的一对多的依赖,让多个观察者对象同时监听某个主题对象,当主题对象发生改变的时候,它的所有依赖者都会收到通知并更新

优点

1、符合开闭原则
2、可以在运行时建立对象之间的联系

后记

在我自己的实际使用中,常常将几种设计模式混杂在一起中,比如将策略模式、模板方法模式等混合在一起。并不一定要拘泥于某项代码的写法。

学习链接

目前B站讲的最好的23种设计模式全套教程(2022最新)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容