当前位置: 首页 > news >正文

基于java的设计模式学习

PS :以作者的亲身来看,这东西对于初学者来说有用但不多,这些东西,更像一种经验的总结,在平时开发当中一般是用不到的,因此站在这个角度上用处不大。

1.工厂模式

1.1 简单工厂模式

我们把new 对象逻辑封装到一共工厂里,通过工厂去实例化对象。用户无需知道逻辑,只需要传入对应的参数就可得到对应的对象。

坏处: 假如说我们这个Me类有个新的子类,那么我们需要对Me工厂的getMeInstance逻辑修改,后面每次增加新的子类也是如此,需要增加多个if else判断。一旦子类变多,该方法就会变得臃肿,可读性变差。

1.2 工厂方法模式

我们再看工厂方法模式,就是在工厂定义一个抽象方法,用来实例化类的。 然后每次新增加一个子类,都会创建一个新的对应工厂,去实现这个方法,return一个新子类。

缺点: 每次增加一新的子类,都会增加新的具体工厂,新的具体工厂只能创建一个具体对象。

1.3 抽象工厂模式

不同于工厂方法模式,父抽象工厂只是提供一个接口,而新的子类工厂可以去实例一种产品。

关于工厂模式,我们可以采用ava反射来实例任何一个对象。

2.单例模式

//  单例模式涉及到懒加载解决线程安全的问题。

通过线程锁、 volatile:直接操作变量主内存解决安全问题。

​​​​public class SingletonDemo {private static ReentrantLock lock = new ReentrantLock(true);private static volatile SingletonDemo singletonDemo; // 考虑到副本 -> 主内存引用// 双重锁检查就是考虑,内存public static SingletonDemo getInstance(){Condition condition = lock.newCondition();if(singletonDemo == null){lock.lock(); // 锁住,防止多次实例化try {lock.lock();singletonDemo = new SingletonDemo();System.out.println("我创建了");}finally {lock.unlock();}}return singletonDemo;}

3.生成器模式

理解:把一个复杂对象对创造,拆分成好几个对象。

就比如说,我们常见的Http对象,我们单一个创建http对象的话由很多字段,所有我们可以给他改成HttpRequest、HttpBody、Reeuqest里面拆分成Method,Contype类型等方式。

所以,我们可以把他一个对象的创造,拆分成好几个对象来构造。,当然一般默认会写默认字段值的,这种就叫生成器模式。

一般生成器模式,喜欢加一个Builder内部类,直接用来创建外部对象。

关于内部类有什么好处? 内部类,能直接访问外部的成员

优化代码结构,相关关联的一般写成内部类。

回调机制: 将内部类,作为参数,作为回调参数传递给。满足条件调用回调函数。

class Main{public static void main(String[] args) {Book book = Book.Builder.newBook().name("qhx").price(24);}
}
class Book {private String name;private Integer price;public Book name(String name){this.name  = name;return this;}public Book price(Integer price){this.price = price;return this;}static class Builder{public static Book newBook(){return new Book();}}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getPrice() {return price;}public void setPrice(Integer price) {this.price = price;}}

4.原型模式

理解: 原型模式,就是对一个对象进行深层拷贝而已(对于对象来说,需要创建一个新对象。)。

1.比如,这个对象创建很复杂,但是我们又要用这个对象,所以直接深拷贝。

2.或者这个对象,需要多次用到,多次创建又很麻烦。

关于原型模式,是否能提升速率,那应该跟深拷贝的方法有关。

1.直接去 new对象,然后进行手动拷贝...,或者通过反射api来进行Bean拷贝。

2.将该对象通过序列化和反序列化的形式。

Book book = Book.Builder.newBook().name("qhx").price(24);ByteArrayOutputStream bom = new ByteArrayOutputStream();
ObjectOutputStream oom = new ObjectOutputStream(bom);
oom.writeObject(book); // 写进去一个对象ByteArrayInputStream bim = new ByteArrayInputStream(bom.toByteArray());
ObjectInputStream oim = new ObjectInputStream(bim);
Book book1 = (Book) oim.readObject();

5.适配器模式

适配器: 用于将用户希望调用的接口,实际上调用的是另一个接口。

目标接口: 定义客户端所期望的接口

适配器: 实现目标接口,并将请求转换为被适配的调用

被适配者: 需要被适配的对象

5.1 类适配器

PS : 看下面,适配器对象实现目标接口,继承了被适配对象。

这样我们调用目标接口的功能,然后实际上调用的是我们继承被适配对象的功能。

// 目标接口
interface AudioPlayer {public void play(String audioType, String fileName);
}// 被适配对象
class Mp3Player {public void playMp3(String fileName) {System.out.println("Playing mp3 file: " + fileName);}
}// 适配器类
class Mp3PlayerAdapter extends Mp3Player implements AudioPlayer{@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("mp3")){this.playMp3(fileName);}}
}

5.2 对象适配器

PS: 看下面,适配器对象已经持有被适配对象,这样我们调用目标接口功能,实际上调用被适配对象的功能。

// 目标接口
interface AudioPlayer {public void play(String audioType, String fileName);
}// 被适配对象
class Mp4Player{public void playMp4(String fileName){System.out.println("Playing mp4 file:" +fileName);}
}// 适配器
class Mp4PlayerAdapter implements AudioPlayer{private Mp4Player mp4Player;public Mp4PlayerAdapter(Mp4Player mp4Player) {this.mp4Player = mp4Player;}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("map")){mp4Player.playMp4(fileName);}}
}

5.3 接口适配器

PS: 当不需要实现一个接口的全部方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。

// 3.接口适配器模式// 目标接口
interface EventListener {public void onEvent1();public void onEvent2();public void onEvent3();
}
// 适配器
abstract class EventListenerAdapter implements EventListener {@Overridepublic void onEvent1() {}@Overridepublic void onEvent2() {}@Overridepublic void onEvent3() {}
}// 具体适配器模式
class MouseEventListener extends EventListenerAdapter {@Overridepublic void onEvent2() {System.out.println("Mouse clicked");}
}

6.装饰者模式

理解:

跟代理模式有点类似,但是跟多强调的是对被装饰者功能的扩展。

代理模式:引入一个代理对象控制对目标对象的访问,主要强调的访问控制和管理,如传入参数和返回值的管理。

组成:

Component(抽象组件):定义了被装饰对象和装饰对象的共同接口。

Concrete Component(具体组件):实现了抽象组件接口,是被装饰的对象。

Decorator(装饰者):实现了抽象组件接口,并持有一个抽象组件对象的引用,可以动态地给组件添加额外的行为。

Concrete Decorator(具体装饰者):具体装饰者是具体的装饰对象,通过扩展装饰者的功能给被装饰对象添加新的行为。

// 抽象组件
interface Student{void run();
}// 被装饰者
class Boy implements Student{@Overridepublic void run() {System.out.println("男孩跑!");}
}// 抽象装饰者
abstract class StudentPlus implements Student{protected Student student;public StudentPlus(Student student){this.student = student;}@Overridepublic void run() {student.run();}
}// 具体装饰者
class BoyPlus  extends StudentPlus{public BoyPlus(Student student) {super(student); // 抽象类,无法直接new,但是有构造器,被继承new}@Overridepublic void run() {student.run();bike();}private void bike(){System.out.println("骑自行车跑!");}
}

7.代理模式

理解:

代理对象和被代理对象实现同一个接口,我们调用代理对象实际上调用

被代理对象,我们实际通过代理对象对被代理对象做了一个管控,通过代理对象的接口间接调用被代理对象的接口,完成对调用参数的过滤和对响应参数管控或者扩展其他功能。

组成:

抽象主题(Subject):定义了目标对象和代理对象的公共接口,客户端可以通过该接口访问目标对象或代理对象。

目标对象(Real Subject):定义了代理对象所代表的真实对象,客户端最终希望访问的就是该对象。

代理对象(Proxy):持有一个指向目标对象的引用,并实现了与目标对象相同的接口,它可以在调用目标对象之前或之后执行一些额外的逻辑。

7.1 静态代理

我们要实现被代理对象的接口,每次针对被代理对象都需要创建一个代理对象。

public class ProxyMode {public static void main(String[] args) {Service serviceProxy = new ServiceProxy(new ServiceImpl());serviceProxy.buyHouse();}
}
// 服务接口
interface Service{void buyHouse();
}// 服务类
class ServiceImpl  implements Service{@Overridepublic void buyHouse() {System.out.println("买房时");}
}// 代理类
class ServiceProxy implements Service{private Service service;public ServiceProxy(Service service) {this.service = service;}@Overridepublic void buyHouse() {System.out.println("买房前!");service.buyHouse();System.out.println("买房后!");}
}

7.2 动态代理

我们不用去实现代理对象,jvm在内存里,帮我们创建代理对象...

实际上,我们这种能传进任意对象,进行代理。

ServiceImpl serviceImpl = new ServiceImpl();
Service serviceProxy1 = (Service)Proxy.newProxyInstance(Service.class.getClassLoader(),new Class[]{Service.class}, new ServiceProxyHandler(serviceImpl)); // 代理处理器
serviceProxy1.buyHouse(); // method
// 服务接口
interface Service{void buyHouse();
}// 服务类
class ServiceImpl  implements Service{@Overridepublic void buyHouse() {System.out.println("买房时");}
}// 动态代理: 通过java的反射api,在jvm内存里面创建java代理对象,但是我们要实现一个代理类。
class ServiceProxyHandler implements InvocationHandler {private Object object;public ServiceProxyHandler(Object object) {this.object = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("买房前!");Object result = method.invoke(object, args);System.out.println("买房后!");return result;}}

8. 外观模式

PS :跟mvc三层架构比较像诶。

 视图层(View)类似于外观模式中的客户端(Client),它负责向用户展示界面,并接收用户的操作。

控制器层(Controller)类似于外观模式中的外观类(Facade),它负责处理用户的操作并调用相应的业务逻辑。

模型层(Model)则类似于外观模式中的子系统(Subsystems),它包含了应用的业务逻辑和数据访问接口。

理解:

假如说,我们要操作某银行系统,实现一个效果:存钱,打开账户,输入存入金额,点击存钱...这个方法是不是很多..

因此,我们可以新建一个外观类,把这些接口统统封装,并对外暴露一个接口存钱接口,用户通过客户端类,调用这个接口,传入参数就能达到这个效果。

层级: 系统类 -> 外观类 -> 客户端类。

组成:

外观类(Facade):外观类是外观模式的核心,它提供了一个简单的接口,用来访问子系统中的一群接口。外观类将客户端与子系统之间的复杂交互关系封装在内部,对客户端隐藏了子系统的复杂性。

子系统(Subsystems):子系统是指外观类所封装的一组接口,用来实现某个复杂的功能。子系统可以包含多个类,但对于客户端来说,只需要知道外观类提供的简单接口即可。

客户端(Client):客户端是调用外观类的代码,它通过外观类提供的简单接口来和系统进行交互。

// 子系统A
class SubSystemA {public void operationA() {System.out.println("SubSystemA: operationA");}
}// 子系统B
class SubSystemB {public void operationB() {System.out.println("SubSystemB: operationB");}
}// 外观类
class Facade {private SubSystemA subSystemA;private SubSystemB subSystemB;public Facade() {subSystemA = new SubSystemA();subSystemB = new SubSystemB();}public void operation() {subSystemA.operationA();subSystemB.operationB();}
}// 客户端
class Client {public static void main(String[] args) {Facade facade = new Facade();facade.operation();}
}

9. 桥接模式

理解:

一个系统有多个功能,每个功能都有各自的接口/抽象类和他们的实现类/继承类,他们之间通过聚合的方式在一起,组成完整的一个系统: 桥接模式是他们直接的具体实现。

组成

Abstraction(抽象类):定义抽象类的接口,维护一个指向Implementor的指针(引用实例)。

RefinedAbstraction(扩充抽象类):扩展抽象类接口,通常通过对抽象类进行子类化来实现[就是抽象类的实现类]。

Implementor(实现类接口):定义实现类的接口,这个接口不一定要与Abstraction的接口完全一致。实际上这两个接口可以完全不同。

ConcreteImplementor(具体实现类):实现Implementor接口,提供具体的实现。

举例:

下面的手机和软件之间的关系。手机有不同的品牌,软件也有不同;

他们的种类各自有个抽象类/接口,Software有个run()方法,然后AppStore和Wx分别有他们的run(),

我们在Phone的抽象类中,拿到了Softaware的引用,并且我能通过setSoftware()传进不同的software实现类,来达到启动不同软件的效果。

Phone apple = new Apple();
apple.setSoftware(new Wx());Apple apple1 = new Apple();
apple1.setSoftware(new AppStore());
interface Software{void run();
}class AppStore implements Software{@Overridepublic void run() {System.out.println("商店启动!");}
}class Wx implements Software{@Overridepublic void run() {System.out.println("微信启动!");}
}abstract class Phone{protected Software software;public void setSoftware(Software software) {this.software = software;}abstract public void run();}class Apple extends Phone{@Overridepublic void run() {software.run();}
}

10. 组合模式

理解:

组合结构中的类,是整体和部分之间的关系。如: 文件(叶节点)和文件夹(容器节点), 文件夹里面能包含文件和文件夹。

组成

  1. 组件(Component):定义了组合中对象的通用接口,可以是抽象类或接口。它声明了一些操作方法,如添加、删除、获取子组件等,这些方法可以有默认实现。
  2. 叶节点(Leaf):代表组合中的叶子对象,它没有子组件。叶节点是组合结构的最基本单元,通常实现组件接口的方法。
  3. 容器节点(Composite):代表组合中的容器对象,它可以包含其他子组件。容器节点实现了组件接口,并提供了添加、删除、获取子组件等方法。
// 文件夹 - 文件之间: 表示整体和部分之间。 一个文件夹,里面包括多个文件
// 客户端可以一致的对待单个对象和组合对象,因为接口是一样的???
// 扩展很容易: 增加新的组件类型,符合开闭原则,在不用改变现有代码的情况下,能够对public class CompositeMode {}// 组件: 定了组合中对象的通用接口。可以是抽象类或其他接口
interface FileSystemComponent{void printName();int getSize();}// 文件类: 叶节点,他没有子组件,是组合结构中的基本单元,通常实现组件接口的方法。
class File implements FileSystemComponent{private String name;private int size;@Overridepublic void printName() {System.out.println("File:" +name);}@Overridepublic int getSize() {return size;}
}
// 文件夹类: 容器节点,代表组合中的容器对象,可以包含其他子组件。容器节点也实现了组件接口,并提供了add/remove/select等方法。
class Folder implements FileSystemComponent{private String name;private List<FileSystemComponent> children;public boolean addComponent(FileSystemComponent fileSystemComponent){return children.add(fileSystemComponent);}public boolean removeComponent(FileSystemComponent fileSystemComponent){return children.remove(fileSystemComponent);}public FileSystemComponent selectComponent(int index){return children.get(index);}public Folder(String name) {this.name = name;this.children = children = new ArrayList<>();}@Overridepublic void printName() {System.out.println("Folder:" +name);for (FileSystemComponent child : children) {child.printName();}}@Overridepublic int getSize() {int totalSize = 0;for (FileSystemComponent child : children) {totalSize += child.getSize();}return totalSize;}
}

11.享元模式

理解:

享元工厂创建享元对象,传入内部状态。享元工厂通过内部状态判断享元对象是否存在,存在不创建,存在创建。根据享元状态创建的享元对象,传入外部参数。

PS: 因为有大量对象,创建太多会占用内存。因此,通过享元模式,我们的将享元对象分为内部状态和外部状态。内部状态,可以理解为是属性;而外部状态,就是通过方法传入的参数之类的。享元工厂负责创建和管理享元对象,通过一个池(集合)存储已经创建好的享元对象,确保对象的共享和复用。

组成:

抽象享元(Flyweight):定义享元对象的接口,声明需要接收外部状态参数的方法。

具体享元(Concrete Flyweight):实现抽象享元接口,存储并管理内部状态。

享元工厂(Flyweight Factory):负责创建和管理享元对象,通过一个池(如集合)来存储已经创建的享元对象,确保对象的共享和复用。

客户端(Client):使用享元对象的客户端,维护外部状态,并将其传入享元对象。

优点:

减少内存使用:通过共享对象的内部状态,减少相同或相似对象的数量,从而减少内存的使用。

提高性能:共享对象可以被多个客户端同时使用,减少了对象的创建和销毁的开销,提高了系统的性能。

简化对象结构:享元模式将对象的状态分为内部状态和外部状态,简化了对象的结构,使得对象更加轻量级。

// 客户端
public class FlyweightMode {public static void main(String[] args) {Car car1 = CarFactory.getCar("长安一号", "ChangAn");Car car2 = CarFactory.getCar("长安二号", "ChangAn");Car car3 = CarFactory.getCar("长安二号", "ChangAn");car1.run("小王");car2.run("小红");car3.run("小白");}
}
// 抽象享元
interface Car{void run(String driver);
}// 享元实体类
class ChangAn implements Car{private String carName;public ChangAn(String carName) {this.carName = carName;}@Overridepublic void run(String driver) {System.out.println(driver + "开着," +carName);}
}// 享元工厂
class CarFactory{private static Map<String,Car> carMap = new HashMap();private CarFactory(){}public static Car getCar(String carName,String type){Car car = carMap.get(carName);if(car == null){if(type.equals("ChangAn")){car =  new ChangAn(carName);carMap.put(carName,car);}}return car;}
}

12.策略模式

理解:

通过外包一层,隔绝算法的实现和算法的调用。用户,只需要知道怎么使用该接口,并得到什么算法实现的结果。

定义:

它定义了一系列的算法,将每个算法封装起来,并使它们可以互相替换。通过这种方式,客户端程序不需要知道每个算法背后的具体实现,而只需要选择合适的算法并调用。

组成:

策略接口(Strategy Interface):用于定义所有支持的算法的公共接口,客户端通过该接口调用算法。

具体策略类(Concrete Strategy Class):实现策略接口,包含了具体的算法实现逻辑。

环境类(Context Class):包含一个策略对象,并提供一个调用策略的方法,客户端通过环境类来调用不同的算法。

public class StrategyMode {public static void main(String[] args) {// 根据跟工厂模式,唯一大的不同,工厂模式,他给我们创建对象;策略模式,是我们自己创建对象Environment environment = new Environment(new QQStrategy());environment.writeData();Environment environment1 = new Environment(new WxStrategy());environment1.writeData();}
}
// 策略接口
interface Strategy{void write();
}// 具体策略类
class QQStrategy implements Strategy{@Overridepublic void write() {System.out.println("数据写入QQ!");}
}class WxStrategy implements Strategy{@Overridepublic void write() {System.out.println("数据写入微信!");}
}// 环境类
class Environment {private Strategy strategy;public Environment(Strategy strategy) {this.strategy = strategy;}public void writeData(){strategy.write();}
}

13.模版模式

理解:

通过父类定义模版方法,定义抽象方法,由子类去实现这些抽象方法,完成算法结构的实现。

组成:

抽象父类(AbstractClass):实现了模板方法,定义了算法的骨架。

具体类(ConcreteClass):实现抽象类中的抽象方法,即不同的对象的具体实现细节。

public class TemplateMode {public static void main(String[] args) {People wang = new WangPeople();wang.run();}
}
// 抽象父类:定义类的骨架
abstract class People{void run(){this.laShen();this.PaoBu();}abstract void laShen();abstract void PaoBu();}// 具体类: 去实现抽象父类的骨架
class WangPeople extends People{@Overridevoid laShen() {System.out.println("小王,拉伸!");}@Overridevoid PaoBu() {System.out.println("小王跑步!");}
}

14.观察者模式

理解:

就是当一个被观察者对象的状态发生改变时,会通知其他观察者对象发生改变。

使用场景

事件驱动编程。观察者模式是事件驱动编程的一种常用实现方式,它通过将 事件源和事件处理分离 ,使得事件源不必知道哪些对象对其状态感兴趣,而只需将事件通知给所有已注册的观察者对象即可。

GUI界面开发。在GUI界面开发中,用户通过某种操作或输入改变了界面上的控件状态,这些状态改变将会被触发并通知给相应的观察者对象,观察者对象根据状态变化来做出相应的更新操作,从而实现界面的实时更新

消息队列系统。消息队列系统通常需要处理大量的异步消息,这些消息可能来自于不同的发送者,而每个发送者又可能有多个接收者。观察者模式可以帮助消息队列系统管理和分发这些消息,保证它们能够被正确地传递和处理。

数据库连接池。在数据库连接池中,观察者模式可以用来监测数据库连接的状态,当某个连接出现问题时,观察者模式可以及时通知其他连接池对象进行处理,从而保证整个连接池的可用性。

订阅系统。订阅系统是指允许用户订阅某个主题或频道,并接收相关信息或内容的系统。观察者模式可以用来实现订阅系统中的事件通知和内容分发功能,从而使得用户能够及时获取到他们感兴趣的信息或内容。

看下面,假如window系统启动时,通知cpu日志和风扇(fs)日志的观察者打印info信息。// 或者说,一台电脑启动,被CPU和风扇的事件监听器监听,监听到之后通知CPU和风扇启动。

public class ObserverMode {public static void main(String[] args) {SystemRunLog systemRunLog1 = new SystemRunLog();SystemRunLog systemRunLog2 = new SystemRunLog();WinSystem winSystem = new WinSystem();winSystem.addLog(systemRunLog1);winSystem.addLog(systemRunLog2);winSystem.run();}
}
// 主题
interface SystemP{void run();
}// 具体主题
class WinSystem implements SystemP{List<Log> list;public WinSystem() {this.list = new ArrayList<>();}@Overridepublic void run(){systemRunInfoLog();}private void systemRunInfoLog() {for (Log log : list) {log.info("启动-");}}// 负责管理观察者public boolean addLog(Log log){return list.add(log);}public boolean removeLog(Log log){return list.remove(log);}}// 观察者
interface Log{void info(String mes);void error(String mes);
}// 具体观察者
class CpuRunLog implements Log{@Overridepublic void info(String mes) {System.out.println("cpu info:" + mes);}@Overridepublic void error(String mes) {System.out.println("cpu error:" +mes);}
}class FsRunLog implements Log{@Overridepublic void info(String mes) {System.out.println("fs info:" + mes);}@Overridepublic void error(String mes) {System.out.println("fs error:" +mes);}
}

15.迭代器模式

理解:

提供一种顺序访问聚合对象中各个元素的方法,而不需要暴露聚合对象的内部表示。

什么是聚合对象?

聚合对象 负责存储和管理一组元素,并提供一种方式来获取迭代器对象,从而使得外部客户端可以通过迭代器访问和遍历聚合对象中的元素,而不必了解其内部表示和结构。

适用场景?

集合类:例如列表、数组等需要遍历元素的容器类。

数据库查询结果集:当需要逐行处理数据库查询结果时,可以使用迭代器模式来遍历结果集。

文件解析:当需要逐行读取文件内容时,可以使用迭代器模式来实现逐行解析。

public class IteratorMode {public static void main(String[] args) {ArrayList<String> objects = new ArrayList<>();objects.add("qhx");objects.add("qhx");objects.add("qhx");Aggregate concreteAggregate = new ConcreteAggregate<>(objects);Iterator<String> iterator = concreteAggregate.createIterator();while (iterator.hasNext()){Object next = iterator.next();System.out.println(next);}}
}

// 迭代器接口
interface Iterator<T>{T next();boolean hasNext();
}// 具体迭代器
class ConcreteIterator<T> implements Iterator<T>{private List<T> list;private int index;public ConcreteIterator(List<T> list) {this.list = list;this.index = 0;}@Overridepublic T next() {if(hasNext()){return list.get(index++);}return null;}@Overridepublic boolean hasNext() {return index  < list.size();}
}// 聚合类
interface Aggregate {Iterator createIterator();
}// 具体聚合类
class ConcreteAggregate<T> implements Aggregate {private List<T> list;public ConcreteAggregate(List<T> list) {this.list = list;}@Overridepublic Iterator createIterator() {return new ConcreteIterator(list);}
}

16.责任链模式

理解:

允许多个对象按照顺序处理请求。在这个模式中,每个对象都有机会处理请求,可以选择自己处理或者将其传递给链中的下一个对象。这样,请求就能在一系列对象之间传递,直到有一个对象处理它为止。也就是多个对象成链状组装在一起,共同处理事务,当满足条件的事务,对象就会处理,不满足就向下一个对象传递。

组成:

抽象处理者(Handler):定义一个处理请求的接口,并包含一个对下一个处理者的引用。它可以是抽象类或接口,规范处理者的行为。

具体处理者(Concrete Handler):继承自抽象处理者,实现处理请求的方法。每个具体处理者都会根据自己的能力来判断是否能够处理该请求,如果能够处理,则进行处理;否则将请求传递给下一个处理者

客户端(Client):创建处理者对象并组成责任链,将请求发送给链的第一个处理者。

//假设我们有一个购买审批系统,需要按照不同的金额级别对购买请求进行审批。
public class ResponsibilityChainMode {public static void main(String[] args) {ClientL clientL = new ClientL();clientL.sendRequest(5000);}
}

// 客户端:负责用户发送请求
class ClientL {private Handler firstHandler;public ClientL() { // 创建客户端时,就初始化责任链()this.firstHandler = new ManagerHandler();Handler handler2 = new DirectorHandler();firstHandler.setNextHandler(handler2);}// 发送请求void sendRequest(int amount){firstHandler.handlerRequest(new PurchaseRequest(amount));}
}// 抽象处理着:拿到下个处理着的引用、处理请求的方法
abstract class Handler{public Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}public abstract void handlerRequest(PurchaseRequest request);
}// 具体处理着:经理
class ManagerHandler extends Handler{@Overridepublic void handlerRequest(PurchaseRequest request) {if(request.amount <= 1000){System.out.println("Manager 可以处理!");}else if(nextHandler != null){ // 传给nextHandler.handlerRequest((request));}}
}// 具体处理着:管理者
class DirectorHandler extends Handler{@Overridepublic void handlerRequest(PurchaseRequest request) {if(request.amount <= 5000){System.out.println("Director 可以处理!");}else if(nextHandler != null){ // 传给nextHandler.handlerRequest((request));}}
}// 请求
class PurchaseRequest {Integer amount; // 金额public PurchaseRequest(Integer amount) {this.amount = amount;}
}

17.命令模式

组成:

命令(Command):定义了执行操作的接口,包括一个执行方法(通常为

execute()

具体命令(Concrete Command):实现了命令接口,将一个接收者对象绑定到一个动作,并在执行方法中调用接收者的相关操作。

接收者(Receiver):执行实际操作的对象。命令对象将请求委派给接收者来执行具体的操作

调用者(Invoker):持有命令对象并调用其执行方法来触发请求操作

客户端(Client):创建具体命令对象,并将其与接收者关联起来,然后将命令对象交给调用者进行处理

ps:行为请求者不应该依赖于单个具体的行为实现者,而是应该通过抽象接口或中介对象来间接地调用实现者。

举例:

假设我们有一个家电控制系统,其中包括电视、音响和灯光等设备。现在我们希望实现一个遥控器,可以通过按钮来控制不同的设备,例如打开电视、关闭音响、调暗灯光等操作。

public class CommandMode {public static void main(String[] args) {RemoteControl remoteControl = new RemoteControl();TVCommand tvCommand = new TVCommand();TV tv = new TV();tvCommand.setTv(tv);remoteControl.setCommand(tvCommand);remoteControl.pressButton();}
}
// 定义一个命令抽象类
interface Command {void execute();
}// 针对电视设备的具体命令类。
class TVCommand implements Command{private TV tv;public void setTv(TV tv) {this.tv = tv;}@Overridepublic void execute() {tv.run();}
}// 电视设备(命令接受者)
class TV {public void run(){System.out.println("电视启动!");}
}// 电视遥控器(命令调用者)
class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton(){command.execute();}
}

好像明白了,命令模式,还是遵循一个调用实例拿到一个抽象对象的引用。

只不过,你看上述,设备抽象接口化好像不太合适,因此中间又加了一层命令抽象化,电视控制器调用具体的命令实现。命令实现拿着具体设备的引用。

进而 遥控器 -> 命令 -> 设备。

18.状态模式

组成:

Context(上下文):上下文是一个包含状态对象的类,它可以 调用状态对象的方法,并在状态对象内部状态发生改变时更新自身的状态

State(状态):状态是一个接口或抽象类,定义了具体状态需要实现的方法。具体的状态类通过继承和实现来实现这些方法。

Concrete State(具体状态):具体状态是状态接口的不同实现,每个具体状态都有自己的行为。

理解:

上下文对象持有状态类,而上下文的行为,依赖于状态类(属性),状态的改变会影响上下文对象的行为改变。

PS:也就是说跟策略模式的实现逻辑类似,只不过客观主体不同?那个在于能调用不同的策略,而这个在于包装对象的行为,依赖于不同状态对象的行为。

public class StateMode {public static void main(String[] args) {Order order = new Order(new PendingPaymentState());order.processOrder();  // 输出:订单待支付order.setState(new PaidState());order.processOrder();  // 输出:订单已支付order.setState(new ShippedState());order.processOrder();  // 输出:订单已发货}
}
// 状态接口
interface State {void handle();
}// 具体状态类:待支付状态
class PendingPaymentState implements State {public void handle() {System.out.println("订单待支付");// TODO: 处理待支付状态的逻辑}
}// 具体状态类:已支付状态
class PaidState implements State {public void handle() {System.out.println("订单已支付");// TODO: 处理已支付状态的逻辑}
}// 具体状态类:已发货状态
class ShippedState implements State {public void handle() {System.out.println("订单已发货");// TODO: 处理已发货状态的逻辑}
}// 上下文类:订单
class Order {private State state;public Order(State state) {this.state = state;}public void setState(State state) {this.state = state;}public void processOrder() {state.handle();}
}

19.备忘录(快照)模式

理解:

有时候需要记录某个时刻的状态,并且在之后去恢复这个状态。

也就是说,备忘录模式提供了一种状态恢复的一种方案。

PS:遵循单一责任原则,每个类根据责任划分,符合解耦,而且这样代码阅读性比较高。

组成:

发起人(Originator):它是 拥有内部状态的对象,需要保存和恢复状态 。它提供了创建备忘录对象以及从备忘录对象中恢复状态的方法

备忘录(Memento):它是用于存储发起人对象内部状态的对象备忘录可以包含发起人对象的部分或全部状态信息

管理者(Caretaker):它负责存储备忘录对象,以便在需要时进行检索和管理

案列:

public class MementoMode {public static void main(String[] args) {TextEditor editor = new TextEditor();TextStateManager stateManager = new TextStateManager();LinkedList<Object> objects = new LinkedList<>();editor.setText("Hello, World!"); // 设置文本stateManager.saveState(editor); // 保存状态editor.setText("Hello, GPT-3.5!"); // 修改文本System.out.println(editor.getText()); // 输出:Hello, GPT-3.5!stateManager.restoreState(editor); // 恢复状态System.out.println(editor.getText()); // 输出:Hello, World!}
}
// 发起人(文本编辑器类)
class TextEditor{private String text;public void setText(String text) {this.text = text;}public String getText() {return text;}public void restore(Memento memento) {text = memento.getText();}
}// 备忘录(文本状态类)
class Memento {private String text;public Memento(String text) {this.text = text;}public String getText() {return text;}
}// 管理者(文本状态管理类)
class TextStateManager {private Stack<Memento> stack = new Stack<>();public void saveState(TextEditor textEditor) {stack.push(new Memento(textEditor.getText()));}public void restoreState(TextEditor textEditor) {if (!stack.isEmpty()) {textEditor.restore(stack.pop());}}
}

20.访问者模式

理解:

针对访问者对不同元素的访问,提供给了不同代码操作;因此,实际上我们考虑访问者(用户调用)和被访问元素类的解耦。

组成

抽象访问者(Visitor):定义了对每个具体元素(ConcreteElement)访问时所产生的具体行为。它包含了访问者的核心逻辑,即具体业务方法,用于访问并处理不同类型的元素对象

具体访问者(ConcreteVisitor):实现了抽象访问者(Visitor)所定义的接口,即定义了对每个具体元素(ConcreteElement)访问时所产生的具体行为。它通过重写抽象访问者中的具体业务方法,实现了对不同类型的元素对象的访问和处理

抽象元素(Element):定义了一个accept()方法,该方法接受一个访问者(Visitor)作为参数并调用该访问者的visit()方法来实现对该元素的访问。它是被访问的对象的抽象表示,其中包含了具体访问者所需要的数据。

具体元素(ConcreteElement):实现了抽象元素(Element)所定义的接口,即实现了accept()方法。它是被访问的对象的具体表示,其中包含了具体访问者所需要的数据。

对象结构(Object Structure):定义了一个容纳元素对象的集合,并提供了一些基本操作,如添加、删除、遍历等。它可以是一个复杂的数据结构或一个简单的集合,其中包含了各种类型的元素对象。

实例:

public class VisitorMode {public static void main(String[] args) {// 但是,针对每种设计模式,我才遵循思想,不遵循绝对设计原则ConcreteVisitor concreteVisitor = new ConcreteVisitor();ConcreteElementA concreteElementA = new ConcreteElementA();concreteElementA.accept(concreteVisitor);// 针对访问了不同元素,提供了不同的行为逻辑。}
}// 抽象访问者:定义了针对某个具体元素访问所产生的具体行为
interface Visitor {void visit(ConcreteElementA element);void visit(ConcreteElementB element);
}// 具体访问者
class ConcreteVisitor implements Visitor {@Overridepublic void visit(ConcreteElementA element) {System.out.println("Visitor is visiting ConcreteElementA");// 对ConcreteElementA进行具体的操作}@Overridepublic void visit(ConcreteElementB element) {System.out.println("Visitor is visiting ConcreteElementB");// 对ConcreteElementB进行具体的操作}
}// 抽象元素: 定义了一个accept()方法,该方法以访问者作为参数,调用visitor方法来完成元素的访问。
interface  Element{void accept(Visitor visitor);
}// 具体元素A
class ConcreteElementA implements  Element{@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 具体元素B
class ConcreteElementB implements  Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 对象结构:定义了一个容纳元素对象的集合
class ObjectStructure {private List<Element> elements = new ArrayList<>();public void addElement(Element element) {elements.add(element);}public void removeElement(Element element) {elements.remove(element);}public void accept(Visitor visitor) {for (Element element : elements) {element.accept(visitor);}}
}

21.中介者模式

// 谈谈我对集中处理和分布式处理的理解,集中处理的好处是,所有文件集中配置,肯定好管理,但是一旦项目大了,需要集中的东西业也越来越多,和这个时候,我们再集中处理,代码可读性不高,因此我们可以按照功能、业务划分模块,在这个模块,我们再集中一起处理,这样代码可读性明显更高!!

为服务,就是在此基础上形成的,代码量变大,针对每个功能模块单独成分成一个模块(一般是直接打包成为一个服务!)。

理解:

中介者模式适用于对象之间存在复杂的交互关系,且希望减少对象之间的直接耦合的情况。通过引入中介者对象,可以将对象之间的交互逻辑进行集中和封装,提高系统的灵活性和可维护性。

一群对象,通过中介者类进行互相交通信?

组成:

中介者(Mediator)

:定义了对象之间的协调和通信接口,通常包含多个通信方法,用于处理不同的交互场景。中介者对象持有对各个对象的引用,负责将接收到的请求转发给合适的对象进行处理

具体中介者(Concrete Mediator)

:实现了中介者接口,负责实际的协调和通信逻辑。它通常需要了解并持有对各个相关对象的引用,以便根据不同的交互情况进行适当的分发和转发。

同事类(Colleague)

:表示一个参与交互的对象,每个同事类都知道中介者对象,并且与其他同事类通过中介者进行通信。同事类之间可以有不同的实现,但它们之间不直接交互,而是通过中介者进行间接通信

具体同事类(Concrete Colleague)

:实现了同事类接口,负责实际的业务逻辑,并通过中介者对象来与其他同事类进行通信和协调。

代码:

public class MediatorMode {public static void main(String[] args) {// 用户先注册聊天室ChatRoomMediator chatRoom = new ChatRoom();User qhx = new User("qhx", chatRoom);User wls = new User("wls", chatRoom);User wxh = new User("wxh", chatRoom);chatRoom.addUser(qhx);chatRoom.addUser(wls);chatRoom.addUser(wxh);qhx.send("hello!");}
}// 中介者接口
interface ChatRoomMediator {public void sendMessage(String message, User user);public void addUser(User user);
}// 具体中介者
class ChatRoom implements ChatRoomMediator {private List<User> users;public ChatRoom() {this.users = new ArrayList<>();}@Overridepublic void sendMessage(String message, User user) {for (User u : users) {if (u != user) {u.receive(message);}}}@Overridepublic void addUser(User user) {this.users.add(user);}
}// 同事类
class User {private String name;private ChatRoomMediator chatRoom;public User(String name, ChatRoomMediator chatRoom) {this.name = name;this.chatRoom = chatRoom;}public void send(String message) {chatRoom.sendMessage(message, this);}public void receive(String message) {System.out.println(name + " received message: " + message);}
}

相关文章:

基于java的设计模式学习

PS &#xff1a;以作者的亲身来看&#xff0c;这东西对于初学者来说有用但不多&#xff0c;这些东西&#xff0c;更像一种经验的总结&#xff0c;在平时开发当中一般是用不到的&#xff0c;因此站在这个角度上用处不大。 1.工厂模式 1.1 简单工厂模式 我们把new 对象逻辑封装…...

组合数学+费用背包+刷表,G2 - Playlist for Polycarp (hard version)

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 G2 - Playlist for Polycarp (hard version) 二、解题报告 1、思路分析 一…...

阿尔泰科技利用485模块搭建自动灌溉系统实现远程控制

自动灌溉系统又叫土壤墒情监控系统&#xff0c;土壤墒情监控系统主要实现固定站无人值守情况下的土壤墒情数据的自动采集和无线传输&#xff0c;数据在监控中心自动接收入库&#xff1b;可以实现24小时连续在线监控并将监控数据通过有线、无线等传输方式实时传输到监控中心生成…...

Python正则表达式中的分组

表达式中的分组 它是可以通过" () “来进行分组&#xff0c;更专业的表达就是捕获组&#xff0c;每个完整的” () “可以分为一组&#xff0c;同时&#xff0c;” () “中还可以嵌套” () "&#xff0c;即组之间还可以存在更小的组 概念 1、当我们在一个正则表达式…...

openstack设置IP直接登录,不需要加dashboard后缀

openstack 实验环境&#xff0c;openstack-t版&#xff0c;centos2009 修改配置文件 [rootcontroller ~]# vim /WEBROOT /etc/openstack-dashboard/local_settings #将dashboard去掉 WEBROOT /dashboard/ #改为 WEBROOT /[rootcontroller ~]# vim /etc/httpd/conf.d/openst…...

PHP宠物店萌宠小程序系统源码

&#x1f43e;萌宠生活新方式&#x1f43e; &#x1f3e1;【一键直达萌宠世界】 你是否也梦想着拥有一家随时能“云撸猫”、“云吸狗”的神奇小店&#xff1f;现在&#xff0c;“宠物店萌宠小程序”就是你的秘密花园&#xff01;&#x1f31f;只需轻轻一点&#xff0c;就能瞬…...

nginx负载均衡实例

实现效果 浏览器输入地址http://nginx服务器ip(:80)/edu/a.html&#xff0c;实现负债均衡效果&#xff0c;平均分配到 服务器ip:8080和 服务器ip:8081进程中。 准备工作 准备两个tomcat&#xff0c;一个监听在8080端口&#xff0c;一个监听在8081端口。也可以准备多个tomcat。…...

正则表达式在Python中的高级应用:从HTML中提取数据

正则表达式在Python中的高级应用&#xff1a;从HTML中提取数据 作为一名资深的Python程序员&#xff0c;我深知正则表达式在文本处理中的重要性。尤其是在处理HTML文档时&#xff0c;正则表达式可以成为我们提取数据的强大工具。在本文中&#xff0c;我将通过一个实际的例子&a…...

docker compose 部署交互模式的容器-以Ubuntu为例

docker compose 部署交互模式的容器-以Ubuntu为例 问题介绍解决方式 同步发布在个人笔记docker compose 部署交互模式的容器-以Ubuntu为例 问题介绍 想通过 docker compose 方式部署一个交互模式的 Ubuntu 容器&#xff0c;但是以平常的方式执行部署后&#xff0c;发现容器被创…...

display: flex 和 justify-content: center 强大居中

你还在为居中而烦恼吗&#xff0c;水平居中多个元素、创建响应式布局、垂直和水平同时居中内容。它&#xff0c;display: flex 和 justify-content: center 都可以完成&#xff01; display: flex&#xff1a;将元素定义为flex容器 justify-content&#xff1a;定义项目在主轴…...

记录贴-idea导入别人的项目

链接: IDEA导入Web项目的三种方式 链接: idea怎么导入别人的maven项目 链接: IDEA 如何导入别人的javaweb项目进行部署...

算法第九天:leetcode59.螺旋矩阵II

给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]示例 2&#xff1a; 输入&#xff1a;n 1 输出&am…...

androidkiller重编译apk失败的问题

androidkiller重编译apk失败 参考&#xff1a; https://blog.csdn.net/qq_38393271/article/details/127057187 https://blog.csdn.net/hkz0704/article/details/132855098 已解决&#xff1a;“apktool” W: invalid resource directory name:XXX\res navigation 关键是编译…...

matlab中plot的一些用法

文章目录 一、基本用法二、绘制多个数据集三、设置线型、颜色四、添加标题和标签五、添加图例六、设置轴范围七、绘制网格八、 在同一图中绘制多个子图九、绘制带误差条的图十、绘制半对数图和对数图十一、绘制填充区域图十二、综合案例 一、基本用法 x 0:0.1:10; y sin(x);…...

Elasticsearch:Retrievers 介绍 - Python Jupyter notebook

在今天的文章里&#xff0c;我是继上一篇文章 “Elasticsearch&#xff1a;介绍 retrievers - 搜索一切事物” 来使用一个可以在本地设置的 Elasticsearch 集群来展示 Retrievers 的使用。在本篇文章中&#xff0c;你将学到如下的内容&#xff1a; 从 Kaggle 下载 IMDB 数据集…...

5 webSocket

webSockets 简介 什么是 websocket webSockets 是一种先进的技术;它可以在用户的浏览器和服务器之间打开交互式通信会话;使用此 API,您可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应 websocket 是一种网络通信协议,是HTML5开始提供的一种在单…...

PD芯片诱骗取电电压给后端小家电用电:LDR6328

在智能家居浪潮的推动下&#xff0c;小家电作为日常生活中不可或缺的一部分&#xff0c;其供电方式的创新与优化正逐步成为行业关注的焦点。随着快充技术的普及&#xff0c;特别是Power Delivery&#xff08;PD&#xff09;协议的广泛应用&#xff0c;一种新型供电模式——利用…...

深入解析Linux文件权限管理:掌握`chmod`和`chown`命令

深入解析Linux文件权限管理&#xff1a;掌握chmod和chown命令 深入解析Linux文件权限管理&#xff1a;掌握chmod和chown命令 大纲&#xff1a;摘要&#xff1a;内容&#xff1a; 1. 引言2. 理解文件权限3. 使用chmod命令4. 使用chown命令5. 综合应用6. 常见问题与解决方案7. 结…...

3.Implementing Controllers

Implementing Controllers 控制器提供了对应用程序行为的访问&#xff0c;这些行为通常通过一个服务接口来定义。控制器解释用户输入&#xff0c;并将其转换为由视图展示给用户的模型。Spring 以非常抽象的方式实现了控制器&#xff0c;使得你能够创建各种各样的控制器。 Spr…...

如何分清楚常见的 Git 分支管理策略Git Flow、GitHub Flow 和 GitLab Flow

Git Flow、GitHub Flow 和 GitLab Flow 是几种常见的 Git 分支管理策略&#xff0c;它们帮助开发团队更高效地管理代码库和协同开发。 Git Flow Git Flow 是一种功能强大的分支管理模型&#xff0c;由 Vincent Driessen 提出&#xff0c;适用于发布周期较长、需要严格管理发布…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...