# 设计模式六大原则
- 开闭原则:继承抽象类并实现抽象方法。抽象方法可以实现但是不能修改
- 单一职责原则:一个类只做一件事儿。发送短信、发送邮件、push通知应该在不同的类中。
- 里氏替换原则:继承时只添加新方法,不重写现有方法
- 接口隔离原则:和一个类只做一件事儿一样。我们在应用中分user、role、message等service
- 依赖倒置原则:controller层注入的是service层而不是impl层就是这一原理
- 迪米特法则:人、驾驶能力、车这三种关系,人只跟驾驶能力交流,不跟车交流。类似mvc、controller、service。mvc只是有调用接口的能力,不要直接跟service交流
# 开闭原则
一个软件实体如类、模块和函数应该对修改封闭,对扩展开放。
// 抽象类定义了扩展点
abstract class PaymentProcessor {
public abstract void processPayment();
}
// 具体实现类
class CreditCardProcessor extends PaymentProcessor {
public void processPayment() {
System.out.println("Processing credit card payment.");
}
}
class PayPalProcessor extends PaymentProcessor {
public void processPayment() {
System.out.println("Processing PayPal payment.");
}
}
// 扩展新的支付方式,不需要修改现有代码
class BitcoinProcessor extends PaymentProcessor {
public void processPayment() {
System.out.println("Processing Bitcoin payment.");
}
}
# 单一职责原则
一个类只做一件事,一个类应该只有一个引起它修改的原因。
// 违反SRP的例子:一个类负责两个职责
class Order {
private double amount;
private String customerName;
public Order(double amount, String customerName) {
this.amount = amount;
this.customerName = customerName;
}
// 处理订单
public void processOrder() {
// 订单处理逻辑
}
// 发送订单确认邮件
public void sendConfirmationEmail() {
// 发送邮件逻辑
}
}
// 遵循SRP的例子:将职责分离到不同的类
class OrderProcessor {
public void processOrder(Order order) {
// 订单处理逻辑
}
}
class EmailService {
public void sendConfirmationEmail(Order order) {
// 发送邮件逻辑
}
}
# 里氏替换原则
子类应该可以完全替换父类。也就是说在使用继承时,只扩展新功能,而不要破坏父类原有的功能。
class Rectangle {
protected int width;
protected int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getArea() {
return width * height;
}
}
// 违反LSP的例子
class Square extends Rectangle {
public Square(int side) {
super(side, side);
}
// 重写了setWidth和setHeight方法,违反了LSP
public void setWidth(int width) {
super.width = width;
super.height = width; // 这使得Square不再是Rectangle的子类型
}
public void setHeight(int height) {
super.width = height;
super.height = height;
}
}
// 遵循LSP的例子
class GoodSquare extends Rectangle {
public GoodSquare(int side) {
super(side, side);
}
// 只添加新方法,不重写现有方法
public void setSide(int side) {
super.width = side;
super.height = side;
}
}
# 依赖倒置原则
细节应该依赖于抽象,抽象不应依赖于细节。把抽象层放在程序设计的高层,并保持稳定,程序的细节变化由低层的实现层来完成。
// 高层模块依赖于抽象
interface IMessageService {
void sendMessage(String message);
}
class EmailService implements IMessageService {
public void sendMessage(String message) {
System.out.println("Sending email: " + message);
}
}
class NotificationService {
private IMessageService messageService;
public NotificationService(IMessageService messageService) {
this.messageService = messageService;
}
public void notifyUser(String message) {
messageService.sendMessage(message);
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
NotificationService notificationService = new NotificationService(new EmailService());
notificationService.notifyUser("Hello, World!");
}
}
# 迪米特法则
又名「最少知道原则」,一个类不应知道自己操作的类的细节,换言之,只和朋友谈话,不和朋友的朋友谈话。
// 违反POLK的例子:类之间存在不必要的交互
class User {
private String name;
private Car car;
public User(String name, Car car) {
this.name = name;
this.car = car;
}
public void drive() {
car.startEngine();
car.drive();
}
}
class Car {
public void startEngine() {
System.out.println("Car engine started.");
}
public void drive() {
System.out.println("Car is driving.");
}
}
// 遵循POLK的例子:减少不必要的交互
class User {
private String name;
private CarController carController;
public User(String name, CarController carController) {
this.name = name;
this.carController = carController;
}
public void drive() {
carController.drive();
}
}
class CarController {
private Car car;
public CarController(Car car) {
this.car = car;
}
public void drive() {
car.startEngine();
car.drive();
}
}
class Car {
public void startEngine() {
System.out.println("Car engine started.");
}
public void drive() {
System.out.println("Car is driving.");
}
}
# 接口隔离原则
客户端不应依赖它不需要的接口。如果一个接口在实现时,部分方法由于冗余被客户端空实现,则应该将接口拆分,让实现类只需依赖自己需要的接口方法。
// 违反ISP的例子:一个接口包含不需要的方法
interface IWorkout {
void run();
void swim();
void liftWeights();
}
// 遵循ISP的例子:将接口拆分成更小的接口
interface IRunner {
void run();
}
interface ISwimmer {
void swim();
}
interface IWeightLifter {
void liftWeights();
}
# 设计模式
# 创建型模式(5种)
对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。
记忆口诀:创工原单建抽(创公园,但见愁)
# 简单工厂模式(不是5种里面的)
cy解释:调用者传入需要什么类型,通过switch case把对象创建出来。多态返回
简单工厂模式违背了单一职责原则、开闭原则。
# 工厂方法模式
cy解释:每种产品创建一个工厂,再通过父类的公共方法制造一个产品。 官方解释:在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
# 抽象工厂模式
cy解释:创建了一个统一的工厂,先new产品工厂,再执行调用创建方法。多态调用 官方解释:它能创建一系列相关或相互依赖的对象,而无需指定具体类。这种模式适用于需要处理产品系列的情况。
# 单例模式
饿汉式、懒汉式(考虑线程安全)、静态内部类
# 建造者模式
builder
# 原型模式
Object 的 clone() 方法就属于原型模式。
# 结构型模式
关注于对象的组成以及对象之间的依赖关系,描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。
记忆口诀: 乔代理组合适配器,享元回家装饰外观
# 桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式。 创建实现类接口,创建实现类,创建抽象父类,定义存储实现类,创建子类。实例化子类时传入实现类实例,子类方法则可调用实现类。
# 代理模式
给某一个对象提供一个代理,并由代理对象控制对原对象的引用 创建对象接口,创建对象类,创建代理类,实例化代理类时传入对象类,由代理类执行对象方法
# 组合模式
又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 创建抽象父类,定义相似属性和方法,创建子类重写抽象方法,达到对外用统一类型引用
# 适配器模式
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。(有相关性但不兼容的结构) 创建一个适配器类,接口A对象的返回值,返回B对象的请求参数类型
# 享元模式
运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式。(共享对象,提高复用性)
# 装饰模式
动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器,与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”
# 外观模式
外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式。
# 行为型模式
关注于对象的行为问题,是对在不同的对象之间划分责任和算法的抽象化;不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
记忆口诀: 访问者写好策略备忘录,观察模版迭代的状态,命令中介解释责任链
# 访问者模式
将数据的结构和对数据的操作分离 对象封装好数据的操作,将对象传递给数据类,由数据类负责调用操作数据的方法,达到数据和操作分离的目的。
# 策略模式
定义了一系列算法,并将每个算法封装起来,使它们可以互换使用,算法的变化不会影响使用算法的用户。 创建一个接口,所有策略实现这个类并重写方法。再创建一个入口类也实现接口,在创建入口类时,传入策略,然后调用入口实现方法执行策略,达到对策略执行的封装。
# 备忘录模式
在不破坏封装的条件下,通过备忘录对象存储另外一个对象内部状态的快照,在将来合适的时候把这个对象还原到存储起来的状态 创建了一个类,用来存储需要备忘对象的状态
# 观察者模式
定义对象的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于她的对象都得到通知并被自动更新 创建一个观察者接口,包含一个update方法。创建一个被观察者父类,存储观察者列表。创建观察和被观察者,将观察者加入被观察者的观察者列表,当被观察者有行为动作时,调用被观察者的父类,遍历通知观察者。
# 模板方法模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 父类编写统一功能,子类重写个性化功能。
# 迭代器模式
提供一种方法访问一个容器对象中的各个元素,而不需要暴露该对象的内部细节 创建迭代器接口,包含hasNext()和next()方法,在类中创建内部类,实现迭代接口,重写两个方法。调用迭代对象的迭代方法将返回迭代对象,即可使用两个方法进行遍历。
# 状态模式
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 抽取状态类,当用户实例化后,调用状态方法
# 命令模式
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作 创建命令接口,创建命令对象,创建客户类,实例化命令对象时传入行为对象,实例化客户对象时传入命令对象,客户对象只需要执行命令方法即可,不需要关心行为对象
# 中介者模式
定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。 创建一个中介类,创意对象类,实例化对象类时传入中介类,所有对象类调用中介方法即可
# 解释器模式
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
# 责任链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 创建一个责任链抽象类,包含一个下级实例和一个处理方法。创建责任链类,重写处理方法,处理完成后调用下一级进行处理。调用时先构建责任链,然后调用第一链接节的处理方法,则可构成责任链处理。