煞赶峙 发表于 2025-6-6 14:49:27

常用的设计模式

设计模式看似把代码改造了很多,其实,只不过是把代码挪动了一下位置,增加了一些小小的变量,删减了一些小小的变量。
历史

设计模式一开始是由一个搞建筑的人提出的。GoF,Gang of Four,四人组。指的是一本书,四个人写的,因为名字太长了,就叫做这个。原书名好像是叫做:《设计模式:面向对象软件设计的基础》
这本书中提出的设计模式一共有23种。
设计原则

设计原则按照字母手写简写可以概括为`SOLID`原则。单一职责原则(Single Responsibility Principle)
开放封闭原则(Open Close Principle)
里氏替换原则(Liskov Substitution Principle)
迪米特法则(Least Knowledge Principle)
接口分离原则(Interface Segregation Principle)
依赖倒置原则(Dependency Inversion Principle)
单一职责

一个模块负责一个功能。比如 controller 层有多个 controller,service 层有多个 service,每个模块负责的功能都不一样。
如果都混在一起,那么:

[*]寻找代码很困难
[*]修改代码很麻烦
开闭原则

对修改关闭,对扩展开放。如果要扩展功能,尽量不要修改原有代码,而是实现接口或者继承父类。
里氏替换原则

S 是 F 的子类,如果 S 的编译类型是 F,那么 S 的行为尽量和 F 保持一致。意思就是子类尽量不要覆盖父类的方法。
override:推翻、覆盖。
之所以被翻译成“重写”,我认为是 override 看起来或者听起来有点像 overwrite,而它确实有“覆盖,重写”的意思,但并不是关键字,而且“重写”听起来不如“覆盖”那么那么容易理解。
迪米特法则

也叫最少知道原则。一个类尽量与自已有直接依赖关系的类或接口产生联系。
比如 controller 中只与 service 层产生直接联系,没有 dao 层的依赖;
明星与经纪人是直接联系,经纪人和粉丝直接联系。
接口隔离原则

不要试图创建一个很庞大的接口,而应该针对特定的功能去设计接口。比如 person 接口有 eat,study,work,sleep 四个方法,那么 Teacher 类和 Student 类实现这个接口的时候,都必须实现这四个方法,但是 Teacher 无需实现 study 方法,Student 类也无需实现 work 方法,这就造成代码冗余了。
更好的方法应该是,创建三个接口:Person,Teacher,Student,Person 只有 eat,sleep 方法,Student 接口只有 study 方法,Teacher 类只有 work 方法。
那么,老师类实现 Person、Teacher 这两个接口,学生类实现 Person、Student 这两个接口。
依赖倒置原则

高层模块尽量依赖抽象,而不是具体的实现类。比如 controller 类应该依赖的是 Service 接口,而不是 Service 实现类。
https://cdn.nlark.com/yuque/0/2024/jpeg/38672378/1732894596042-622fec80-3a4c-4ff3-97c9-ac7acaa56c49.jpeg
有什么好处呢?
如果要替换 Service 实现类,那么就只需要替换实现类,而Service,controller 是不用变的。
创建型

单例模式

饿汉式

1. 构造器私有化2. 创建静态对象3. 提供外部统一访问方法package singleton.case1;

/**
* 单例模式:饿汉式
*/
public class Singleton1 {
    /**
   * 必须是静态的,如果不是静态的,那么 getInstance 方法就无法使用这个变量名
   * 静态方法只能使用静态成员。
   * 因为非静态成员是属于对象的,但是调用非静态成员必须创建对象。
   */
    private static Singleton1 instance = new Singleton1();

    private Singleton1() {

    }

    public static Singleton1 getInstance() {
      return instance;
    }
}为什么 getInstance 方法是静态的?
因为如果是非静态的,那么必须创建对象,来调用这个方法,但是构造器是不能被外部调用的。
为什么 instance 是静态的?
如果不是静态的,那么 getInstance 方法就无法使用这个变量名。
为什么静态方法只能使用静态成员?
静态方法不属于对象,属于类,因此调用静态方法的时候,是类在调用。方法体中,返回一个对象,返回的是方法调用者的对象,也就是类对象,所以 instance 是静态的。
如果是非静态方法,那么就是对象在调用,方法体中,返回的对象,是属于对象的。对象的成员可以是静态的,也可以是非静态的。
非静态方法返回的对象,默认是属于 this 的,this 表示当前方法的调用者(实例对象)。这也就是为什么静态方法不能出现 this 的原因。
总结:
方法体中出现 this,this 表示当前方法的调用者,调用者是实例对象;
静态方法的调用者是类本身,因此静态方法中不可能出现 this。也不可能出现非静态成员,因为非静态成员是和实例对象相关联的。
工厂模式

一个方法,一个参数,就能创建指定的产品看到XXXFactory形式的类,就要想到这是一个工厂类,它使用了工厂模式,例如 Spring 的BeanFactory、Mybatis 的 SqlSessionFactory。
简单工厂模式

工厂直接创建产品package com.cskaoyan.fatory.simple;


import com.cskaoyan.fatory.bean.Animal;
import com.cskaoyan.fatory.bean.Pig;
import com.cskaoyan.fatory.bean.Rabbit;

/**
* 简单工厂
*/
public class SimpleAnimalFactory {


    /**
   * 提供一个方法,根据不同的参数,获取不同的对象实例
   * @param animalName
   * @return
   */
    public static Animal getAnimal(String animalName) {
      if (animalName.equals("pig")) {
            return new Pig();
      }

      if (animalName.equals("rabbit")) {
            return new Rabbit();
      }

      return null;
    }
}package com.cskaoyan.fatory.simple;

import com.cskaoyan.fatory.bean.Animal;

public class Case1 {

    public static void main(String[] args) {

      Animal pig = SimpleAnimalFactory.getAnimal("pig");
      Animal rabbit = SimpleAnimalFactory.getAnimal("rabbit");

      int m = 0;
    }
}工厂方法模式

由子工厂来创建产品package com.cskaoyan.fatory.method;

import com.cskaoyan.fatory.bean.Animal;


/**
*
* 工厂方法设计模式:
*
* 通过不同的工厂实现类,就可以获取不同的对象实例
*
* 工厂方法中,只有一个方法,只能生产单个产品
* 而抽象工厂中,有多个方法,可以生产的是一个产品矩阵
*/
public interface AnimalFactory {

    Animal getAnimal();
}package com.cskaoyan.fatory.method;

import com.cskaoyan.fatory.bean.Animal;
import com.cskaoyan.fatory.bean.Pig;

public class PigAnimalFactory implements AnimalFactory{
    @Override
    public Animal getAnimal() {
      return new Pig();
    }
}package com.cskaoyan.fatory.method;

import com.cskaoyan.fatory.bean.Animal;
import com.cskaoyan.fatory.bean.Rabbit;

public class RabbitAnimalFactory implements AnimalFactory{
    @Override
    public Animal getAnimal() {
      return new Rabbit();
    }
}抽象工厂模式

一个工厂有多个方法,可以生产一系列产品public abstract class AbstractFurnitureFactory {

    public abstract TV createTV();
    public abstract Freezer createFreezer();
}public class MiFurnitureFactory extends AbstractFurnitureFactory{
    @Override
    public TV createTV() {
      return new MiTV();
    }

    @Override
    public Freezer createFreezer() {
      return new MiFreezer();
    }
}public class HaierFurnitureFactory extends AbstractFurnitureFactory{
    @Override
    public TV createTV() {
      return new HaierTV();
    }

    @Override
    public Freezer createFreezer() {
      return new HaierFreezer();
    }
}public class OrderFurniture {
    public static void main(String[] args) {
      MiFurnitureFactory miFactory = new MiFurnitureFactory();
      TV tv = miFactory.createTV();
      Freezer freezer = miFactory.createFreezer();
      System.out.println("tv instanceof MiTV = " + (tv instanceof MiTV));
      System.out.println("freezer instanceof MiFreezer = " + (freezer instanceof MiFreezer));
    }
}建造者模式

形式:`XXXBuilder`使用场景:创建复杂对象。一步一步形成一个完整的对象,每一步又可能涉及到其他对象。
现有的例子:StringBuilder、Minio、ES、@Builder 注解……
StringBuilder
package com.cskaoyan.builder.case1;

public class Case1 {

    public static void main(String[] args) {

      /**
         * 建造者模式的代码
         */
      StringBuilder stringBuilder = new StringBuilder();
      stringBuilder.append("hello")
      .append(" ")
      .append("cskaoyan")
      .append(" ")
      .append("2025")
      .append("!");

      String content = stringBuilder.toString();
      System.out.println(content);
    }
}

// 对比set:这种方式更加连续,更加紧凑,set 面对复杂对象容易出错。@Builder注解
// 这个注解,其实就是在编译阶段,帮助我们生成这个对象的builder类
// 但是,需要注意的是,一旦某个类被添加了@Builder注解,那么就意味着这个类没有无参构造方法了
// 没有无参构造方法,
    // <1> 那么就意味着不能直接new对象了
    // <2> 那么也意味着,在和很多的框架整合的时候,可能会出现问题
                // mybatis
                // FastJSON
                // RedissonClient
      // 为什么这些框架会有问题呢?
      // 比如使用RedissonClient存一个teacher对象到Redis中,那么此时Redis中存储的是Teacher对象的JSON字符串
      // 但是在取这个对象的时候,首先RedissonClient会从Redis中查询到这个JSON字符串
      // 然后需要把这个JSON字符串转化为Teacher对象
                  // 使用无参构造方法创建一个teacher对象
                  // 设值
      // 因为现在增加了@Builder注解之后,没有无参构造方法,所以此时就会报错

// 记结论
    // 使用@builder注解的时候,需要配合 @NoArgsConstructor注解 和 @AllArgsConstructor注解一起使用结构型

代理模式

行为型

责任链模式

上下文对象可以注册到容器中吗?不可以,因为上下文对象中有值,每个订单不同的订单id。
哪些对象可以复用?
对象里面的数据可以复用,这个对象就能注册到容器中。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 常用的设计模式