常用的设计模式
设计模式看似把代码改造了很多,其实,只不过是把代码挪动了一下位置,增加了一些小小的变量,删减了一些小小的变量。
历史
设计模式一开始是由一个搞建筑的人提出的。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 实现类。
有什么好处呢?
如果要替换 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。
哪些对象可以复用?
对象里面的数据可以复用,这个对象就能注册到容器中。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek-R1本地部署如何选择适合你的版本?看这里
· 开源的 DeepSeek-R1「GitHub 热点速览」
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 揭秘 Sdcb Chats 如何解析 DeepSeek-R1 思维链
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
2024-01-31 关于bootstrap的导航条无法恢复toggle的问题