设计模式

本文深入解析设计模式的三大类型:创建型、结构型和行为型模式,探讨了工厂方法、单例、建造者、适配器等模式的应用场景与优缺点。同时,阐述了面向对象设计原则,如开闭原则、单一职责原则、依赖倒置原则等,帮助读者理解如何设计更加灵活、可维护的软件系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 设计模式-类型

1 创建型模式

Creational Pattern

对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件结构更加清新,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使真个新系统的设计更加符合单一职责原则。

创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。

工厂方法模式 抽象工厂模式 建造者模式 单例模式 原型模式

2 结构型模式

结构型模式

适配器模式 装饰者模式 代理模式 外观模式 桥接模式 组合模式 享元模式

3 行为型模式

策略模式 观察者模式 责任链模式 备忘录模式 模板方法模式 迭代器模式 中介者模式 命令模式 访问者模式 解释器模式 状态模式

二 设计模式-原则

面向对象(封装,继承,多态,抽象,接口的定义和实现)

1 开闭原则

所有原则的基础。对扩展开放,对修改关闭。

2 单一职责原则

Single Responsibility Principle

定义:不要存在多于一个导致类变更的原因

优点:降低类的复杂度,提高类的可读性,提高系统的可维护性,降低变更引起的风险。

3 迪米特法则(最少知道原则)

Law of Demter / The Least Knowledge Principle

定义:一个对象应该对其他对象保持最少的了解。又叫最少知道原则。

优点:降低类之间的耦合度

一个类只与他的朋友类进行交互

直接的朋友:每个对象都会和其他对象有耦合关系,只要两个对象有耦合关系,我么就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接朋友,而出现在局部变量中的类不是直接朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。

4 里氏替换原则

Liskov Substitution Principle

定义:一个软件实体如果适用一个父类的话,那一定适用于子类,所有引用父类的地方必须能透明地适用子类的对象,子类对象能替换父类对象,而程序逻辑不变。

引申定义:子类可以扩展父类的功能,但不能改变父类原有的功能。

含义1:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。

含义2:子类可以增加自己特有的方法。

优点1:约束继承泛滥,开闭原则的一种体现。

优点2:加强程序的健壮性,同时变更时也可以做到非常好的兼容性 提高程序的维护性、扩展性。降低需求变更时引入风险。

5 依赖倒置原则

Dependence Inversion Principle

定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象

抽象不应该依赖细节;细节应该依赖抽象

针对接口编程,不要针对实现编程

优点:可以减少类之间的耦合度、提高系统的稳定性,提高代码的可读性和可维护性,可降低修改程序所造成的风险。

6 接口隔离原则

Interface Segregation Principle

定义:用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。

一个类对一个类的依赖应该建立在最小接口上

建议单一接口,不要建立庞大臃肿的接口

尽量细化接口,接口中的方法尽量少

注意适度原则,一定要适度

优点:符合我们场所的高内聚低耦合的设计思想,从而使得类具有很好的可读性、可扩展性和可维护性。

7 合成(组合)/聚合复用原则

定义:尽量使用对象的组合/聚合,而不是集成关系达到软件复用的目的。

优点:可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。

三 设计模式

简单工厂模式

Simple Factory

工厂方法模式

Factory Method

抽象工厂模式

Abstract Factory

使用目的:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

优点:

一个调用者想创建一个对象,只需要知道其名称就可以了。

扩展性高,如果想增加一个产品,只需要扩张一个工厂类就可以。

屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:

每增加一个产品时,都要增加一个具体类和对应的实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同事也增加系统具体类的依赖。

使用场景:

1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器器等,用户可以选择记录到什么地方。

2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

3、设计一个连接服务器的框架,需要三个协议,POP3、IMAP、HTTP,可以这三个作为产品类,共同实现一个接口。

4、比如Hibernate换数据库只需换方言和驱动就可以。

身边的工厂模式:

JDK给开发者听了Executors这个类,可以让用户产生ThreadPoolExecutor和使用ThreadPoolExecutor分离开,比如可以让Executors提供一个单线程的线程池newSingleThreadExecutor newFixedThreadPool newCachedThreadPool newScheduledThreadPool,让开发者可以不用关心线程池是如何去实现的,直接使用Executors创建的ThreadPoolExecutor。

Connection connection = DriverManager.getConnection()

Logger log = LoggerFactory.getLogger

面试被问工厂模式——这一篇真够了

单例模式

构造函数私有

1、饿汉模式

HungrySingleton

2、懒汉模式

LazySingleton

3、双重检查懒汉模式

LazyDoubleCheckSingleton

volatile避免指令重排序

4、静态内部类

InnerClassSingleton

5、枚举

EnumSingleton

6、容器单例模式

ContainerSingleton

HashMap

7、ThreadLocal单例

反射攻击

序列化和反序列化

Object readResolve()

例子1 饿汉式

java.lang.Runtime 

private static Runtime currentRuntime = new Runtime();

例子2 容器

java.awt.Desktop

例子3

package org.apache.ibatis.executor;

public class ErrorContext {

  private static final ThreadLocal<ErrorContext> LOCAL = ThreadLocal.withInitial(ErrorContext::new);

  private ErrorContext() {
  }

  public static ErrorContext instance() {
    return LOCAL.get();
  }
}

例子4

懒汉式单例。不需要事先创建好,只要在第一次真正用到的时候再创建就可以了。因为很多时候并不常用Java的GUI和其中的对象。如果使用饿汉单例的话会影响JVM的启动速度。

java.awt.Toolkit#getDefaultToolkit()

public abstract class Toolkit {

    private static Toolkit toolkit;

    public static synchronized Toolkit getDefaultToolkit() {
        if (toolkit == null) {
            java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                public Void run() {
                    Class<?> cls = null;
                    String nm = System.getProperty("awt.toolkit");
                    try {
                        cls = Class.forName(nm);
                    } catch (ClassNotFoundException e) {
                        ClassLoader cl = ClassLoader.getSystemClassLoader();
                        if (cl != null) {
                            try {
                                cls = cl.loadClass(nm);
                            } catch (final ClassNotFoundException ignored) {
                                throw new AWTError("Toolkit not found: " + nm);
                            }
                        }
                    }
                    try {
                        if (cls != null) {
                            toolkit = (Toolkit)cls.newInstance();
                            if (GraphicsEnvironment.isHeadless()) {
                                toolkit = new HeadlessToolkit(toolkit);
                            }
                        }
                    } catch (final InstantiationException ignored) {
                        throw new AWTError("Could not instantiate Toolkit: " + nm);
                    } catch (final IllegalAccessException ignored) {
                        throw new AWTError("Could not access Toolkit: " + nm);
                    }
                    return null;
                }
            });
            loadAssistiveTechnologies();
        }
        return toolkit;
    }
}

以上代码是Toolkit类的单例实现。这里类加载时只静态声明了私有toolkit并没有创建Toolkit实例对象,延迟加载加快了JVM启动速度。单例模式作为一种创建模式,在依赖加载的时候应用了另一种创建对象的方式,不是new新的对象,因为Toolkit本身是个抽象类不能实例化对象,而是通过反射机制加载类并创建新的实例。

建造者模式

原型模式

深拷贝和浅拷贝,深克隆和浅克隆。重要的是看拷贝的是不是地址。

外观模式

定义:又叫门面模式,提供一个统一的接口,来方位子系统中的一群接口

外观模式定义了一个高层接口,让子系统更容易使用

适用场景

子系统越来越复杂,增加外观模式听简单的调用接口

构建多层系统结构,利用外观对象作为每层的入口,简化层间调用

优点:

简化了调用过程,无需深入了解子系统,防止带来风险。

减少系统依赖,松散耦合

更好划分访问层次

符合迪米特法则,即最少知道原则

缺点:

增加子系统、扩展子系统行为容易引入风险

不符合开闭原则

适配器模式

两种实现方式,一种是继承,一种是组合

例子:org.springframework.web.servlet.DispatcherServlet

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

org.springframework.web.servlet.HandlerAdapter
HandlerFunctionAdapter
HttpRequestHandlerAdapter
RequestMappingHandlerAdapter
SimpleControllerHandlerAdapter
SimpleServletHandlerAdapter

装饰者模式

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

提供了比继承更有弹性的替代方案(扩展原有对象功能)

适用场景

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

动态的给一个对象添加功能,这些功能可以再动态的撤销

优点:

继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能。

通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同效果

符合开闭原则

缺点:

会出现更多的代码,更多的类,增加程序复杂性

动态装饰时,多层装饰会更复杂

享元模式

组合模式

桥接设计模式

定义:将抽象部分与它的具体实现部分分离,使它们都可以独立变化

通过祝贺的方式建立两个类之间的联系,而不是继承

适用场景

抽象和具体实现之间增加更多的灵活性

一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展

不希望使用继承,或因为多层继承导致系统类的个数剧增

优点

分离抽象部分及其具体实现部分

提高了系统的可扩展性

符合开闭原则

符合合成复用原则

缺点:

增加了系统的理解和设计难度

需要正确识别出系统中两个独立变化的维度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值