文章目录
- 什么是设计模式?
- 设计模式的分类
- 创建型模式
- 创建型类类型
- 工厂方法模式
- 创建型对象型
- 抽象工厂模式
- 生成器模式
- 原型模式
- 单例模式
- 结构型模式
- 结构型类类型
- 适配器模式
- 结构型对象型
- 桥接模式
- 组合模式
- 装饰器模式
- 外观模式
- 享元模式
- 代理模式
- 行为型模式
- 行为型对象型
- 命令模式
- 责任链模式
- 迭代器模式
- 中介者模式
- 观察者模式
- 备忘录模式
- 状态模式
- 策略模式
- 访问者模式
- 行为型类类型
- 模板方法模式
- 解释器模式
温馨提示:看个人理解的时候结合下方代码食用更佳,理解是基于代码基础上的,注意看代码中的注释部分!!!
什么是设计模式?
设计模式是一种在软件开发中广泛使用的经过验证的最佳实践,用于解决常见的软件设计问题。设计模式提供了一种在特定情境下解决问题的方法,可以在设计和编码过程中引导开发人员做出明智的决策,说人话就是各种编程大牛前辈根据他们的编码经验,针对不同的业务场景,留下的一套最佳实践模板,好让我们在缺乏编码经验的同时也能够写出较为优雅的代码,当然看得懂设计模式和在真实业务场景中加以实践完全是天和地的关系,所以需要一定的代码量及业务场景支撑才能领会其精髓所在!
设计模式的分类
上图有两个适配器模式,个人看来是一样的,如有不同理解,欢迎小伙伴们评论区交流
创建型模式
创建型类类型
工厂方法模式
官方定义
定义一个用于创建对象的接口,但让子类决定实例化哪个类。
UML图
个人理解
- 针对定义的理解:代码中的
product
就是我们想要的对象,Factory
就是创建这个对象的接口,然后main
方法中我们使用factoryXXX.createInstance()
延迟创建了我们想要的对象,就像是一个生产线,根据不同的需求生产不同的产品。 - 该模式的好处:
- 封装对象创建逻辑: 工厂方法模式将对象的创建逻辑封装在一个独立的工厂类中,使得客户端无需关心具体的对象创建细节,只需要通过工厂类来创建对象。这样可以降低客户端与具体产品类之间的耦合,提高代码的灵活性和可维护性。
- 通过接口/抽象类定义对象的创建标准: 工厂方法模式通过接口或抽象类定义了对象的创建标准,客户端只需关注接口或抽象类,而不需要关心具体的产品类。这样可以实现客户端与产品类的解耦,使得产品类的变更对客户端无影响。
- 可扩展性强: 工厂方法模式可以轻松地扩展新的产品类,只需要创建对应的具体工厂类即可,而无需修改客户端代码。这种扩展性使得工厂方法模式在面对新的产品需求时非常灵活,可以快速适应变化。
- 提供了一种统一的对象创建方式: 工厂方法模式可以将对象的创建逻辑集中管理,从而实现一种统一的对象创建方式。这样有助于提高代码的一致性和可维护性,减少了代码重复和混乱。
- 支持多态性: 工厂方法模式通过返回抽象类型或接口类型的对象,使得客户端可以通过统一的接口来使用不同的具体产品对象,从而实现多态性。这有助于提高代码的灵活性和可拓展性。
总的来说,工厂方法模式提供了一种灵活、可扩展、可维护的对象创建方式,帮助客户端实现了解耦合,降低了代码的复杂性,是一种常用的设计模式,适用于需要灵活管理对象创建过程的场景。
代码
public class simpleFactoryModel {
public static void main(String[] args) {
Factory factoryA = new FactoryA();
Factory factoryB = new FactoryB();
Product instanceA = factoryA.createInstance();
Product instanceB = factoryB.createInstance();
instanceA.info();
instanceB.info();
}
}
interface Product{
void info();
}
interface Factory {
public Product createInstance();
}
class FactoryA implements Factory {
@Override
public Product createInstance() {
return new productA();
}
}
class FactoryB implements Factory {
@Override
public Product createInstance() {
return new productB();
}
}
class productA implements Product{
@Override
public void info() {
System.out.println("AAAAAAAAA");
}
}
class productB implements Product{
@Override
public void info() {
System.out.println("BBBBBBBBBBBB");
}
}
/*
* 相较于简单工厂模式,工厂模式解决了前者违反的开闭原则问题
* */
* 版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
创建型对象型
抽象工厂模式
官方定义
提供了一个接口,用于创建一系列相关或依赖的对象,而不需要指定具体的类
UML图
个人理解
- 针对定义的理解
相较于前面的工厂方法模式,首先二者在代码层面比较相似,使用AllAbstractFactory
代替了Factory
,个人理解为工厂模式好比一个工厂,这个工厂里可以生产各种类型的东西,既可以生产食品也可以生产衣服,物品类型跨度较大,而抽象工厂模式则是将工厂分成了多个隔间,一个隔间下只生产单类型的商品,例如A隔间只生产衣服,B隔间只生产食物,AB隔间就被抽象成了AbstractProductAA
和AbstractProductBB
,那么实现AbstractProductAA
的产品类型一定是衣服,实现AbstractProductBB
的产品一定是食物,使得整个工厂内部的职责划分更为清晰,好比你作为一个参观者来这个工厂参观,你想直奔生产衣服的地方去,而如果在工厂方法模式中,你可能会发现这个工厂中生产衣服的地方遍布于各个角落,但是在抽象工厂方法模式中,你可以一眼看到生产衣服的地方,没有第二处,后者的好处相比大家也就知道了。 - 该模式的好处
- 提供一种高层次的抽象:抽象工厂模式通过提供抽象工厂接口和抽象产品接口,定义了一种高层次的抽象,使得客户端可以通过这些抽象接口来创建产品族,而无需关心具体产品的细节。这样可以降低客户端与具体产品类之间的耦合度,提高代码的灵活性和可维护性。
- 实现产品族的一致性:抽象工厂模式通过一组抽象产品接口定义了产品族,确保了产品族中的不同产品具有一致的接口和行为。这有助于保持产品族的一致性,避免了产品之间的不兼容性,使得产品的替换和扩展更加方便。
- 支持产品的变化和扩展:抽象工厂模式允许在不修改客户端代码的情况下替换整个产品族,从而实现了产品的变化和扩展。通过创建新的具体工厂类和产品类,可以轻松地引入新的产品变种或扩展产品线,而不会对客户端代码造成影响。
- 提供了一种统一的产品创建方式:抽象工厂模式将一组相关的产品创建逻辑集中在一个工厂中,从而实现了一种统一的产品创建方式。这样有助于提高代码的一致性和可维护性,减少了代码重复和混乱。
- 支持多态性:抽象工厂模式通过返回抽象类型的对象,使得客户端可以通过统一的接口来使用不同的具体产品对象,从而实现多态性。这有助于提高代码的灵活性和可拓展性。
- 有助于实现解耦和:抽象工厂模式将产品的创建逻辑封装在工厂类中,客户端只需关注抽象工厂接口和抽象产品接口,而不需要关心具体的产品和工厂类。这样可以实现客户端与具体产品和工厂类的解耦,使得系统更加灵活和可维护。
总的来说,抽象工厂模式提供了一种灵活、可扩展、可维护的产品族创建方式,帮助客户端实现了解耦和,降低了代码的复杂性,适用于需要管理产品族并保持一致性的场景。
代码
package AllPattern.AbstractFactory;
/**
* 抽象工厂设计模式
* @author CZJ
*/
public class AbstractFactory {
public static void main(String[] args) {
productAA1 productAA = new CreateFactory().createProductAA();
productBB1 productBB = new CreateFactory().createProductBB();
productAA.infoA();
productBB.infoB();
}
}
class productAA1 implements AbstractProductAA {
@Override
public void infoA() {
System.out.println("AA1的信息");
}
}
class productBB1 implements AbstractProductBB {
@Override
public void infoB() {
System.out.println("BB1的信息");
}
}
interface AbstractProductAA {
void infoA();
}
interface AbstractProductBB {
void infoB();
}
//Factory1中负责创建AA1 和 BB1
class CreateFactory implements AllAbstractFactory {
@Override
public productAA1 createProductAA() {
return new productAA1();
}
@Override
public productBB1 createProductBB() {
return new productBB1();
}
}
//总工厂,在这个工厂里可以创建一系列的产品
interface AllAbstractFactory {
AbstractProductAA createProductAA();
AbstractProductBB createProductBB();
}
/*
* AllPattern.AbstractFactory.AllAbstractFactory:是总的工厂,工厂中可以创建各式各样的产品,例如这里面的AA产品和BB产品,返回值即为对应产品的接口
* CreateFactory则是进行实现,返回对应的产品
* */
生成器模式
官方定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
UML图
个人理解
- 针对定义的理解
对象的创建完全由生成器类(这里是Builder1
)负责(public Product product = new Product();
),我们将对象想成一座房子,生成器类就是帮我们生成一座房子的框架,并在之后为其添砖加瓦,而对象的表示工作则由房子类(Product
)自己承担(show
方法),这就叫表示与创建分离,这样我创建同一个房子对象,确实可以创建不同的表示(show1()、show2()......
) - 该模式的好处
- 封装复杂对象的创建过程:生成器模式通过将复杂对象的创建过程封装在一个生成器类中,将创建逻辑从客户端代码中分离出来。这样可以降低客户端的复杂性,将对象的创建过程抽象化和封装化,使得客户端更加关注对象的组装而不是创建过程。
- 支持创建不同表示的对象:生成器模式允许通过不同的生成器类创建不同表示的对象,从而满足不同的需求。每个生成器类都可以有自己的实现逻辑,可以根据需要创建不同的对象实例,从而支持创建多种不同的对象表示。
- 提供细粒度的控制:生成器模式允许客户端通过指定不同的生成器对象来控制对象的创建过程。客户端可以根据需要选择不同的生成器对象,从而控制对象的创建细节,例如属性的赋值顺序、属性的默认值等,从而灵活地创建对象。
- 支持逐步构建复杂对象:生成器模式允许逐步构建复杂对象,每个生成器类负责构建对象的一部分。客户端可以通过调用生成器类的不同方法来逐步构建对象,从而实现对象的组装过程。这样可以降低复杂对象的构建难度,使得对象的构建过程更加可控和可扩展。
- 提高代码复用性:生成器模式可以将对象的创建过程抽象化和封装化,使得可以在不同的场景中复用相同的生成器类,从而提高代码的复用性。生成器模式还可以通过继承或者实现接口的方式,对生成器类进行扩展和定制,从而满足不同的需求,提高了代码的灵活性和可扩展性。
- 有助于实现解耦和:生成器模式将复杂对象的创建过程封装在生成器类中,客户端只需关注生成器接口和生成器的调用顺序,而不需要关心具体的对象创建细节。这样可以实现客户端与具体对象创建过程的解耦,从而使得系统更加灵活和可维护。
总的来说,生成器模式提供了一种灵活、可扩展、可维护的对象创建方式,封装了复杂对象的创建过程,提供了细粒度的控制,支持逐步构建复杂对象,提高了代码复用性,并有助于实现解耦和,适用于需要创建复杂对象并灵活
代码
package AllPattern.builderPattern;
import java.util.ArrayList;
import java.util.List;
/**
* 生成器模式
*
* @author CZJ
*/
public class builderPattern {
public static void main(String[] args) {
Director director = new Director();
builder1 builder1 = new builder1();
director.Construct(builder1);
builder1.getResult().show();
}
}
class Director {
public void Construct(Builder builder) {
builder.buildPart();
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
class builder1 extends Builder {
public Product product = new Product();
@Override
void buildPart() {
product.add("A");
product.add("B");
product.add("C");
product.add("D");
product.add("E");
}
@Override
Product getResult() {
return product;
}
}
abstract class Builder {
//添加产品构件
abstract void buildPart();
//输出产品
abstract Product getResult();
}
class Product {
//产品中可能存在的构件的集合
List<String> list = new ArrayList<>();
//添加构建方法
public void add(String compomentName) {
list.add(compomentName);
}
//输出产品的具体信息
public void show() {
System.out.println("该产品有以下构件:\n");
for (String compoment : list) {
System.out.println(compoment);
}
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
原型模式
官方定义
通过复制现有对象来创建新对象,避免了使用构造函数创建对象的开销。
UML图
个人理解
- 针对定义的理解
该模式很好理解,其实就是自己实现一个java.lang.Object
类下的clone()
方法,调用a对象的clone方法即可获得一个与该对象完全相同的对象,避免了使用构造函数创建对象的开销,就像是复制一张图片来创建多张相同的图片。 - 该模式的好处
- 避免重复的初始化过程:通过使用原型模式,可以避免重复的对象初始化过程,因为新对象可以通过复制现有对象的状态而获得,从而减少了对象创建时的资源消耗和性能开销。
- 提高对象创建性能:与直接创建新对象相比,使用原型模式可以在某些情况下提高对象创建的性能。这是因为对象的复制(克隆)操作通常比创建新对象的初始化过程更加高效。
- 简化对象创建过程:原型模式通过将对象的创建过程封装在原型对象中,使得创建新对象的过程更加简化和灵活。客户端只需基于现有对象进行克隆操作,而无需关心对象的具体创建细节,从而降低了客户端的复杂度。
- 支持动态对象创建:原型模式可以支持动态地创建新对象,因为可以在运行时通过克隆现有对象来创建新对象,而无需在编译时确定对象的具体类型。这对于需要根据运行时条件来创建对象的情况非常有用。
- 保护对象的状态:原型模式通过复制现有对象的状态来创建新对象,从而可以保护现有对象的状态不被修改。这对于需要保持对象状态的情况非常有用,例如在多线程环境中创建对象时,可以避免对象状态的竞态条件。
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
所以,原型模式具有避免重复初始化、提高对象创建性能、简化对象创建过程、支持动态对象创建以及保护对象状态等优点,特别适用于需要创建新对象时避免资源消耗和性能开销的场景。
代码
package AllPattern.prototypePattern;
/**
* 原型模式
* 通俗点说就是克隆对象用的
*
* @author CZJ
*/
public class prototypePattern {
public static void main(String[] args) {
Product product = new Product("11", "阿杰");
System.out.println(product.toString());
Product cloneProduct = (Product) product.Clone();
System.out.println(cloneProduct.toString());
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
class Product implements protoType {
private String id;
private String name;
public Product() {
}
@Override
public String toString() {
return "Product{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
public Product(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object Clone() {
Product objectProduct = new Product();
objectProduct.id = this.id;
objectProduct.name = this.name;
return objectProduct;
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
interface protoType {
Object Clone();//克隆方法
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
单例模式
官方定义
保证一个类只能创建一个实例,并提供全局访问点
UML图
个人理解
- 针对定义的理解
一个类只能创建一个实例,单例模式的写法有很多,下面代码描述的是饿汉式,即类在初始化时就将该类的实例创建好了,后面调用的getInstance
方法始终用的是这个实例,与之对应的还有懒汉式、双检锁类型。 - 该模式的好处
- 保证唯一实例:单例模式可以确保一个类只能创建一个对象实例,从而保证了系统中只有一个唯一的实例存在。这对于某些资源有限或者需要全局统一管理的情况非常有用,例如全局配置信息、线程池、缓存等。
- 提供全局访问点:单例模式提供了一个全局的访问点,可以在任何地方访问到该唯一实例。这样可以方便地从不同的地方获取该实例,避免了传递对象实例的复杂性和冗余代码。
- 避免重复创建对象:单例模式可以避免在多次创建对象时造成资源浪费和性能开销,因为只有第一次创建时才会真正实例化对象,后续的请求都直接返回已经创建好的唯一实例。
- 控制对象的生命周期:单例模式可以控制对象的生命周期,确保在整个系统运行期间只有一个实例存在。这对于需要控制对象的创建、初始化、销毁等操作时非常有用,避免了对象的不一致状态和资源泄漏。
- 提供全局共享资源:单例模式可以用来管理全局共享的资源,例如数据库连接池、日志记录器等。这样可以在系统中统一管理和复用这些资源,提高系统性能和资源利用率。
所以,单例模式具有保证唯一实例、提供全局访问点、避免重复创建对象、控制对象的生命周期以及提供全局共享资源等优点,特别适用于需要确保全局只有一个实例存在,并且需要控制对象的生命周期和提供全局访问点的场景。但需要注意,单例模式也可能会引入全局状态和单点故障的问题,因此在使用时需要慎重考虑。
代码
package AllPattern.SinglePattern;
/**
* 单例模式
* @author CZJ
*/
public class SingletonPattern {
public static void main(String[] args) {
single singles = single.getInstance();
single singles1 = single.getInstance();
single singles2 = single.getInstance();
System.out.println(singles1.getNumber() + " " + singles2.getNumber() + " " + singles.getNumber());
singles.setNumber(77);
System.out.println("改变后...");//永远只有一个对象
System.out.println(singles1.getNumber() + " " + singles2.getNumber() + " " + singles.getNumber());
}
}
class single{
private int number;
private static single singles = new single(66);
private single(int number){
this.number = number;
}
public int getNumber(){
return this.number;
}
public void setNumber(int number){
this.number = number;
}
public static single getInstance(){//这里用static的目的是静态上下文环境下只能使用静态参数
return singles;
}
}
结构型模式
结构型类类型
适配器模式
官方定义
将一个类的接口转换成客户端所期望的另一种接口。
UML图
个人理解
- 针对定义的理解
就像是一个插头转换器,比如我的手机是USB接口的,但是现在只有一根Type-C的数据线,那么就可以用适配器进行转换,使我的USB接口可以使用typec接口的线,下面的代码也是基于该例子编写的。 - 该模式的好处
- 兼容不同接口或类:适配器模式可以解决不同接口或者类之间的不兼容性问题。当需要使用一个已经存在的类或接口,但其接口与现有代码不兼容时,适配器模式可以通过转换接口或者类的方式,使得它们可以协同工作,从而避免了代码重构或者修改现有代码的情况。
- 重用现有代码:适配器模式可以重用现有的代码,从而提高代码的复用性。当需要在新的环境中使用已经存在的类或接口时,适配器模式可以通过适配器将其包装成符合新环境要求的接口,而无需修改原有代码,从而节省了重写或者修改代码的成本。
- 分离关注点:适配器模式可以将不同接口或者类之间的转换逻辑封装到适配器中,从而将不同的关注点分离开来。这样可以提高代码的可维护性和可扩展性,使得系统更加灵活和易于维护。
- 提供灵活性:适配器模式可以提供灵活性,使得系统可以适应不同的接口或者类变化。当需要适应新的接口或者类时,只需要编写新的适配器,而不需要修改原有的代码,从而减少了对原有代码的侵入性,提高了系统的扩展性。
- 促进代码组织和清晰度:适配器模式可以将转换逻辑集中到适配器中,从而使得代码组织更加清晰,减少了代码中的重复和冗余。适配器模式可以将不同接口或者类之间的转换逻辑隔离,使得代码更加清晰和易于理解。
所以,适配器模式具有兼容不同接口或类、重用现有代码、分离关注点、提供灵活性以及促进代码组织和清晰度等优点,特别适用于需要在不同接口或者类之间进行转换的场景,从而提高代码的复用性、可维护性和灵活性。
代码
package AllPattern.AdapterPattern;
/**
* 适配器模式
* @author CZJ
*/
public class AdapterPattern {
public static void main(String[] args) {
Usb usb = new Adapt();
usb.specifyRequest();//由usb 转换成了 typeC
}
}
class Adapt extends Usb {
TYPE_C typeC = new TYPE_C();
@Override
public void specifyRequest(){
typeC.Request();
}
}
class Usb {
public void specifyRequest() {
System.out.println("俺是USB插头!!!");
}
}
class TYPE_C {
public void Request() {
System.out.println("俺是TYPE_C插头!!!");
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
结构型对象型
桥接模式
官方定义
将抽象部分与实现部分分离,使它们可以独立地变化。
UML图
个人理解
- 针对定义的理解
举个例子,我现在要建造一座桥,有5种产品和5种颜色供我选择,如果按照传统方式,我可能需要创建25个类,一个类规定一种产品及对应的颜色,产品与具体颜色是完全绑定死的,而有了桥接模式,它将抽象部分(产品)和实现部分(颜色)分离开来,通过一个桥接接口(Bridge)将它们连接起来。这样,你只需要创建少数几个抽象和实现的类,然后通过组合它们的方式,就可以轻松地创建不同类型的桥了。 - 该模式的好处
- 解耦抽象和实现:桥接模式将抽象部分和实现部分解耦,使得它们可以独立地变化。这意味着可以在不影响彼此的情况下,分别修改抽象和实现的部分。这样一来,当需要增加新的抽象部分或实现部分时,不需要修改已有的代码,只需添加新的抽象类或实现类即可。
- 提高可扩展性:由于抽象部分和实现部分被解耦,桥接模式可以轻松地扩展系统的功能。可以通过增加新的抽象类或实现类来引入新的功能,而不会对已有的代码产生影响。这使得系统更加灵活,能够应对未来的需求变化。
- 简化继承关系:相比于多层继承或多重继承,桥接模式使用组合的方式来连接抽象部分和实现部分,避免了类的爆炸性增长和复杂的继承关系。这使得代码更加清晰和易于维护,减少了继承带来的耦合问题。
- 提高代码复用性:桥接模式可以通过共享实现部分来提高代码的复用性。不同的抽象类可以共享同一种实现类,从而避免了代码的重复。这样可以提高代码的效率和可维护性。
- 提供灵活性:桥接模式可以提供灵活性,使得系统可以适应不同的抽象和实现变化。当需要引入新的抽象部分或实现部分时,只需创建新的抽象类或实现类,并通过桥接接口连接它们,而不需要修改已有的代码,从而减少了对现有代码的侵入性。
所以,桥接模式的好处包括解耦、提高可扩展性、简化继承关系、提高代码复用性以及提供灵活性等。
代码
package AllPattern.BridgePattern;
/**
* 桥接模式
* @author CZJ
*/
public class BridgePattern {
public static void main(String[] args) {
productA productA = new productA();
color color = new red();
productA.setColor(color);
productA.setName("产品1");
productA.Operition();
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
class productA extends Product {
@Override
public void Operition() {
color.OpertionalImpl(this.getName());
}
}
abstract class Product {
private String name;
protected color color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setColor(color color) {
this.color = color;
}
public color getColor() {
return this.color;
}
public abstract void Operition();
}
class blue implements color {
@Override
public void OpertionalImpl(String name) {
System.out.println(name + ":蓝色");
}
}
class red implements color {
@Override
public void OpertionalImpl(String name) {
System.out.println(name + ":红色!");
}
}
interface color {
void OpertionalImpl(String name);
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
组合模式
官方定义
将对象组织成树形结构,并通过一致的方式对待单个对象和组合对象。
UML图
个人理解
- 针对定义的理解
四个字:众生平等!不管你是父级元素还是子级元素,只要让我处理,那么你们都是平等的,不存在操作上的处理差异,下面的代码以文件和文件夹的关系解释了这一说法,在我们以往的思想里(至少在博主的思想中),文件夹有点是文件的"父类"的意思,往往是一个文件夹中包含着多个文件,但反过来则不行,如果对文件夹和文件进行处理,理应区别对待,但是在组合模式中则不是这样,处理文件夹及文件的操作都是一样的,不存在明显的区别,这也解释了官方定义中的一致的方式的含义。 - 该模式的好处
- 统一处理方式:组合模式允许将对象组织成树形结构,其中包含了叶子节点和容器节点。叶子节点和容器节点都实现了相同的接口,因此可以使用相同的方式对待它们,从而统一了对待叶子节点和容器节点的处理方式。这简化了对复杂对象结构的操作和管理。
- 灵活的对象组织方式:组合模式允许通过将对象组织成树形结构来灵活地管理和组织对象。可以随时添加、删除或替换叶子节点和容器节点,从而实现了动态的对象组织方式。这使得组合模式在处理复杂的对象关系和结构时非常有用。
- 提供统一的接口和行为:组合模式通过共享相同的接口和行为,使得叶子节点和容器节点可以统一地对待。这简化了客户端的代码,减少了对不同类型对象的特定处理逻辑,提高了代码的可读性和维护性。
- 支持嵌套结构:组合模式允许在容器节点中嵌套其他容器节点,从而支持多层嵌套的对象结构。这使得组合模式在处理复杂的嵌套结构时非常有用,例如文件系统中的目录结构、组织机构中的部门结构等。
- 可以灵活地操作整体和部分:组合模式允许对整个对象树和单个节点进行操作,从而可以灵活地在整体和部分之间进行操作。这使得组合模式在对整体和部分之间进行一致性操作时非常有用,例如对整个对象树进行遍历、搜索、过滤、排序等操作。
所以,组合模式的好处包括统一处理方式、灵活的对象组织方式、提供统一的接口和行为、支持嵌套结构以及可以灵活地操作整体和部分等。这使得组合模式在处理复杂的对象结构和关系时具有很大的优势。
代码
package AllPattern.CompositePattern;
import java.util.ArrayList;
import java.util.List;
/*c
组合模式
*/
public class CompositePattern {
public static void main(String[] args) {
// 父类名 对象名 = new 子类名();
AbstractFile root = new Folder("root");//创建文件夹
AbstractFile folderA = new Folder("folderA");
AbstractFile folderB = new Folder("folderB");
AbstractFile fileC = new File("fileC");//创建文件
AbstractFile fileD = new File("fileD");
AbstractFile fileE = new File("fileE");
//组织文件夹和文件之间的层级关系
root.Add(folderA);
root.Add(folderB);
root.Add(fileC);
folderA.Add(fileD);
folderA.Add(fileE);
//输出文件及文件夹的名字
print(root);
}
//该方法很好的诠释了众生平等的概念,由于传递的参数是抽象文件类,所以其两个实现类在代码块中都是调用相同的代码,显然,他们是想要递归遍历文件夹下的所有子文件或文件夹
static void print(AbstractFile file) {
file.printName();
List<AbstractFile> childrenList = file.getChildren();
if (childrenList == null) return;
// for (对象类型 对象名 : 遍历对象)
for (AbstractFile children : childrenList) {
// children.printName();
print(children);
}
}
}
abstract class AbstractFile {//抽象文件类
protected String name;
public void printName() {//打印文件或者文件夹的名字
System.out.println(name);
}
public abstract boolean Add(AbstractFile file);//当实现类是文件夹时,可以向其中添加文件
public abstract boolean Remove(AbstractFile file);//当实现类是文件夹时,可以从其中删除文件
public abstract List<AbstractFile> getChildren();//当实现类是文件夹时,可以获取该文件夹下的所有文件
}
class Folder extends AbstractFile {//文件夹实现类
private List<AbstractFile> childrenList = new ArrayList<AbstractFile>();//用来装位于该文件夹下的所有文件
public Folder(String name) {
this.name = name;
}
@Override
public boolean Add(AbstractFile file) {
return childrenList.add(file);
}
@Override
public boolean Remove(AbstractFile file) {
return childrenList.remove(file);
}
@Override
public List<AbstractFile> getChildren() {
return childrenList;
}
}
class File extends AbstractFile {//文件实现类
public File(String name) {
this.name = name;
}
@Override
public boolean Add(AbstractFile file) {
return false;
}
@Override
public boolean Remove(AbstractFile file) {
return false;
}
@Override
public List<AbstractFile> getChildren() {
return null;
}
}
装饰器模式
官方定义
动态地给对象添加新的功能,同时不改变其接口。
UML图
个人理解
- 针对定义的理解
所有人都要吃饭,但是柴同学吃完饭还要运动一会儿,那么我们就需要针对柴同学这类人加以特殊的装饰(使用装饰器A),让其实现吃完饭还能运动这一系列动作,如果吃完饭还有更精彩的节目,还可以再加多个装饰器(装饰器B、装饰器C等等),下面的代码就是将吃饭的概念换成学习,将运动的概念换成写作业和考试,将柴同学这类人换成学生再尝试理解一下,一句话:不改变其接口的前提下添加新功能,就像是给一幅画加上相框。
- 该模式的好处
- 动态扩展功能:装饰器模式允许在不修改原始对象的情况下,动态地添加新的功能或行为。通过将功能的实现封装在装饰器类中,可以在运行时通过组合多个装饰器来动态地扩展对象的功能。这样可以实现一种灵活的方式来添加、移除或修改对象的行为,而无需修改原始对象的代码,从而遵循了开放-封闭原则。
- 分离关注点:装饰器模式将功能的实现从原始对象中分离出来,使得每个装饰器只关注特定的功能或行为。这样可以实现功能的高内聚,使得代码更加清晰、简洁和易于维护。同时,装饰器模式也支持不同组合的装饰器,从而可以灵活地组合和调整功能,以满足不同的需求。
- 可嵌套的装饰器:装饰器模式支持将多个装饰器嵌套在一起,从而形成一个装饰器链。每个装饰器可以根据需要进行灵活组合,从而实现多层的功能扩展。这使得装饰器模式非常适用于需要复杂的功能组合和配置的场景,从而提供了更大的灵活性和可定制性。
- 不破坏现有代码:装饰器模式通过对原始对象进行装饰,而不是修改原始对象的代码,从而不破坏现有的代码结构和功能。这对于已经存在的稳定的代码和系统来说是非常有价值的,因为可以通过装饰器模式来增加新的功能,而无需对已有的代码进行修改和测试。
- 可透明的功能扩展:使用装饰器模式,装饰器和被装饰对象的接口保持一致,从而对客户端来说是透明的。客户端可以像使用原始对象一样使用装饰器,而不需要关心装饰器的具体实现。这样可以实现功能的无缝扩展,而不会对客户端代码产生影响。
所以,装饰器模式的好处包括动态扩展功能、分离关注点、可嵌套的装饰器、不破坏现有代码以及可透明的功能扩展等。这使得装饰器模式在需要对对象进行动态功能扩展和灵活组合的场景中非常有用
代码
package AllPattern.DecoratorPattern;
/**
* 装饰器模式
*
* @author CZJ
*/
public class DecoratorPattern {
public static void main(String[] args) {
person person = new student("张三");
person.Operation();
System.out.println("\n---------我是分割线---------");
person = new DecratorA(person);
person = new DecratorB(person);
person.Operation();
}
}
class DecratorB extends Decorator {
public DecratorB(person person) {
this.person = person;
}
@Override
public void Operation() {
person.Operation();
System.out.println("此处为新添加的职责,我认为是考试");//加强的部分
}
}
class DecratorA extends Decorator {
public DecratorA(person person) {
this.person = person;
}
@Override
public void Operation() {
person.Operation();//先将未加强前做的事做了
System.out.println("此处为新添加的职责,我认为是写作业");//加强的部分
}
}
//装饰器,可以当做个buff,我要给这个人加个buff,所以我要用他的一些属性及行为,所以继承它
abstract class Decorator extends person {
protected person person;//指针,指向被加强的对象
}
//将抽象人实体化成学生,其姓名和职责是什么
class student extends person {
public student(String name) {
this.name = name;
}
@Override
public void Operation() {
System.out.println(name + "的职责是学习");//
}
}
//抽象的人的姓名以及可能做的操作
abstract class person {
public String name;
public abstract void Operation();
}
外观模式
官方定义
提供一个简化的接口,将复杂的子系统封装起来,使得客户端更加方便地使用。
UML图
个人理解
- 针对定义的理解
最简单的一种模式,将繁杂的功能打包到一个包裹中,只需要包裹中内置了访问这些繁杂功能的接口,用某个功能只需调用包裹下的对应接口即可
- 该模式的好处
- 简化接口:外观模式通过提供一个简化的接口,将多个复杂的子系统或对象进行封装,从而使得客户端的调用变得简单和直观。外观模式隐藏了底层系统的复杂性,对客户端提供了一个更加简洁和易于使用的接口,从而降低了客户端的学习成本和使用难度。
- 降低耦合度:外观模式可以将客户端与复杂子系统或对象之间的耦合度降低到最低。客户端只需要和外观接口进行交互,而不需要和各个子系统或对象直接交互。这样可以实现系统的解耦,减少了不必要的依赖关系,从而提高了系统的灵活性、可维护性和可扩展性。
- 提供了系统的抽象层:外观模式可以将底层系统的复杂性隐藏在一个抽象层之下,从而提供了系统的高层抽象。这样可以实现系统的模块化和分层设计,使得系统的不同部分可以独立演化和修改,而不会影响到其他部分。这有助于保持系统的灵活性和可维护性。
- 提高了系统的性能和效率:外观模式可以对客户端的请求进行优化和管理,从而提高了系统的性能和效率。例如,外观模式可以将多个复杂的请求合并为一个简单的请求,从而减少了请求的数量和传递的数据量,提高了系统的响应速度和资源利用率。
- 易于维护和扩展:由于外观模式将系统的复杂性隐藏在一个外观接口之后,因此对系统的维护和扩展变得更加容易。当需要修改系统的功能或增加新的功能时,只需要在外观类中进行修改或扩展,而不需要修改客户端代码或底层子系统的代码。这样可以降低系统的维护成本,并且不会对系统的稳定性产生不良影响。
所以,外观模式的好处包括简化接口、降低耦合度、提供了系统的抽象层、提高了系统的性能和效率,以及易于维护和扩展等。这使得外观模式在需要对复杂系统进行封装和提供简洁接口的场景中非常有用。
代码
package outside.M8;
public class FacadePattern {
public static void main(String[] args) {
Facade facade = new Facade();
facade.methodA();
facade.methodB();
facade.methodC();
}
}
class Facade {
SubSystemOne subSystemOne;
SubSystemTwo subSystemTwo;
SubSystemThree subSystemThree;
public Facade() {
subSystemOne = new SubSystemOne();
subSystemTwo = new SubSystemTwo();
subSystemThree = new SubSystemThree();
}
public void methodA() {
subSystemOne.methodOne();
}
public void methodB() {
subSystemTwo.methodTwo();
}
public void methodC() {
subSystemThree.methodThree();
}
}
class SubSystemOne {
public void methodOne() {
System.out.println("执行子系统一的功能");
}
}
class SubSystemTwo {
public void methodTwo() {
System.out.println("执行子系统二的功能");
}
}
class SubSystemThree {
public void methodThree() {
System.out.println("执行子系统三的功能");
}
}
享元模式
官方定义
共享大量细粒度的对象,从而减少内存占用和提高性能。
UML图
个人理解
- 针对定义的理解
"元"就是细粒度的意思,元数据元数据,自然是小的数据,大量的小的数据会造成数据的冗余,所以如果可以共享这些"小的数据"就好了,所以叫享元模式,如果某些数据已经存在,就不要再创建它了,省的浪费额外的空间或时间,详细理解请看下方代码注释
- 该模式的好处
- 节省内存:享元模式通过共享相似对象的内部状态,从而节省了内存空间。对于那些包含大量相似数据的对象,使用享元模式可以显著减少系统的内存消耗,提高系统的性能和效率。
- 提高性能:由于享元模式可以共享对象的内部状态,从而减少了对象的数量,降低了系统的复杂度,提高了系统的性能。在需要创建大量相似对象的场景中,使用享元模式可以有效地减少对象的创建和销毁操作,从而提升系统的性能。
- 提高对象的复用性:享元模式将对象的内部状态与外部状态分离,使得对象的内部状态可以被共享和复用。这样可以减少对象的创建和销毁,提高对象的复用性,降低了系统的资源消耗,增加了系统的灵活性和可维护性。
- 简化系统结构:享元模式可以将对象的内部状态和外部状态分离,从而简化了系统的结构。对象的内部状态可以由享元工厂进行管理和共享,而外部状态可以由客户端进行管理,这样可以使系统更加清晰、简洁和易于维护。
- 支持大规模对象共享:享元模式适用于需要创建大规模相似对象的场景,例如在图形界面、游戏引擎、网络通信等领域。通过使用享元模式,可以有效地管理大量对象的内部状态,从而减少内存消耗,提高系统的性能和效率。
所以,享元模式的好处包括节省内存、提高性能、提高对象的复用性、简化系统结构,以及支持大规模对象共享等。这使得享元模式在需要处理大量相似对象的场景中非常有用
代码
package outside.M9;
import java.util.*;
public class FlyWeightPattern {
public static void main(String[] args) {
ShapeFactory factory = new ShapeFactory();
Random random = new Random();
String[] colors = {"red", "blue", "green", "white", "black"};//5种颜色的圆
for (int i = 1; i <= 100; i ++ ) {//不会出现map中明明已经有了某个颜色的圆,这里依然创建的情况
int x = random.nextInt(colors.length); // [0 ~ 4]
Shape shape = factory.getShape(colors[x]);
System.out.print("第" + i + "个圆:");
shape.draw(random.nextInt(2022), random.nextInt(528));
}
}
}
class ShapeFactory {
private Map<String, Shape> map = new HashMap<String, Shape>();
public Shape getShape(String key) {//专用于返回一个形状,map中有则直接返回,没有则创建后返回,“有则直接返回”就体现了享元的概念,有就不要创建了
if (!map.containsKey(key)) {
map.put(key, new Circle(key));//没有则创建并放入map
System.out.println("create color:" + key + " circle");
}
return map.get(key);
}
}
abstract class Shape {//抽象的形状
protected String color;
public abstract void draw(int x, int y);//形状绘制方法
}
class Circle extends Shape {//圆形实现类
public Circle(String color) {
this.color = color;
}
@Override
public void draw(int x, int y) {
System.out.println("draw a color:" + color + " circle x:" + x + " y:" + y);
}
}
代理模式
官方定义
为其他对象提供一个代理或者占位符,以控制对原始对象的访问,并且在访问原始对象时提供额外的功能。
UML图
个人理解
- 针对定义的理解
明星和经纪人的关系,明星登台前,经纪人帮他料理一些事,明星下台后,经纪人帮他料理一些事,你明星只需要在我让你上台的时候你上去就行了,其他杂事经纪人来解决,经纪人就是代理Proxy
,明星就是RealSubject
- 该模式的好处
- 控制对原始对象的访问:代理模式可以通过代理对象来限制对原始对象的访问,从而实现对对象访问的控制。例如,可以在代理对象中加入权限验证的逻辑,只有具有特定权限的用户才能访问原始对象。
- 增加额外的功能:代理模式可以在不修改原始对象的情况下,通过代理对象为原始对象提供额外的功能。例如,可以在代理对象中添加缓存、懒加载、日志记录等功能,从而在不影响原始对象的情况下,为其提供增强的功能。
- 降低耦合性:代理模式可以将客户端与真实主题对象解耦,客户端只需要与代理对象进行交互,不需要直接与真实主题对象进行交互。这可以降低系统的耦合性,使得系统更加灵活和易于维护。
- 远程访问:代理模式可以在客户端和真实主题对象之间引入代理对象,从而实现远程访问。例如,可以通过代理对象在客户端和服务器之间进行网络通信,从而实现远程调用。
- 性能优化:代理模式可以通过代理对象对原始对象进行懒加载、缓存等操作,从而优化系统性能。例如,可以在代理对象中缓存一些耗时的计算结果,从而避免重复计算,提高系统性能。
所以,代理模式的好处在于可以通过引入代理对象来控制对原始对象的访问、增加额外的功能、降低耦合性、实现远程访问以及优化性能。在需要对对象访问进行控制和增加功能的场景中,代理模式是一种非常有用的设计模式。
代码
package outside.M10;
public class ProxyPattern {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
proxy.buy();
}
}
interface Subject {//明星需要干的事
public void buy();
}
class Proxy implements Subject {//紧急人
protected RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void buy() {
System.out.println("办理购买前的手续");//明星上台前经纪人干的事
realSubject.buy(); // 付钱
System.out.println("办理购买后的手续");//明星下台后经纪人干的事
}
}
class RealSubject implements Subject {//明星
@Override
public void buy() {
System.out.println("付钱");
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
行为型模式
行为型对象型
命令模式
官方定义
将请求封装成对象,从而使得可以用不同的请求来参数化客户端,并支持请求的排队、记录和撤销。
UML图
个人理解
- 针对定义的理解
命令模式就像在餐厅点餐一样。顾客(请求的发起者)在点餐时将自己的请求(命令)告诉服务员(命令对象),服务员将这个请求封装成订单(命令对象)并交给厨师(命令的执行者)。厨师根据订单中的具体菜品(命令的具体执行细节)来准备食物(执行请求)。这样,顾客不需要直接和厨师交流,而是通过服务员来与厨师交互,实现了请求的发起者和执行者的解耦。
- 请求的封装:命令模式将请求封装成一个对象,包含了请求的具体细节,如何执行该请求以及可能需要的参数等。
- 解耦请求的发起者和执行者:命令模式通过将请求封装成对象,将请求的发起者和执行者解耦,使得它们不需要直接交互,从而降低了系统的耦合度。
- 支持撤销和重做:命令模式可以通过保存命令对象的状态,从而支持请求的撤销和重做操作。
- 支持扩展和灵活性:命令模式可以很容易地扩展和添加新的命令对象,从而增加系统的灵活性和可扩展性。
- 支持日志和事务:命令模式可以在执行命令前后记录命令的日志信息,从而支持事务和日志记录等功能。
- 该模式的好处
- 解耦请求的发起者和执行者:命令模式将请求封装成对象,使得请求的发起者和执行者解耦。发起者不需要知道具体的执行细节,只需通过命令对象来发送请求,从而降低了系统的耦合度,增加了系统的灵活性和可维护性。
- 支持撤销和重做:命令模式可以通过保存命令对象的状态来支持请求的撤销和重做操作。这对于一些需要撤销和重做功能的系统非常有用,比如编辑器软件、游戏等。
- 支持扩展和灵活性:命令模式可以很容易地扩展和添加新的命令对象,从而增加系统的灵活性和可扩展性。可以方便地引入新的命令对象,而无需修改已有的代码。
- 支持日志和事务:命令模式可以在执行命令前后记录命令的日志信息,从而支持事务和日志记录等功能。这对于一些需要记录操作日志或实现事务管理的系统非常有用。
- 简化高层操作:命令模式可以将一系列操作封装成一个命令对象,从而简化了高层操作的复杂性。可以将多个操作封装成一个命令对象,从而简化了调用这些操作的过程。
- 可以实现异步操作:命令模式可以在命令对象中包含异步执行的操作,从而实现异步操作的功能。这对于一些需要异步处理的场景,比如网络请求、消息发送等非常有用。
总的来说,命令模式通过将请求封装成对象,解耦了请求的发起者和执行者,提供了一种灵活、可扩展和可维护的方式来处理请求,同时支持撤销和重做、支持扩展和灵活性、支持日志和事务等功能,使得系统更加灵活、可维护和可扩展。
代码
package AllPattern.CommandPattern;
/**
* @author CZJ
*/
public class CommandPattern {
public static void main(String[] args) {
tv tv = new tv();//创建命令的接收者
onCommond onCommond = new onCommond(tv);//具体的命令与接收者进行绑定
Invoker invoker = new Invoker(onCommond);//创建命令的调用者
invoker.Execute();//实施命令
System.out.println("--------------------");
offCommand offCommond = new offCommand(tv);
Invoker invoker1 = new Invoker(offCommond);
invoker.Execute();
}
}
class Invoker extends Command {
private Command command;
public Invoker(Command command) {
this.command = command;
}
@Override
public void Execute() {
command.Execute();
}
}
//客户端通过调用接收者的Action方法进执行命令
class tv {
void Action() {
}
//打开电视方法
void turnOn() {
System.out.println("电视机打开了!!!");
}
void turnOff() {
System.out.println("电视机关闭了!!!");
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
//具体的打开电视命令,这个命令会有一个接收者
class onCommond extends Command {
private tv tv;
public onCommond(tv tv) {
this.tv = tv;
}
@Override
public void Execute() {
tv.turnOn();
}
}
class offCommand extends Command {
private tv tv;
public offCommand(tv tv) {
this.tv = tv;
}
@Override
public void Execute() {
tv.turnOff();
}
}
//抽象的命令
abstract class Command {
public abstract void Execute();
}
责任链模式
官方定义
它允许多个对象按照指定的顺序处理请求,直到其中一个对象能够处理该请求为止
UML图
个人理解
- 针对定义的理解
将可能可以把这件事解决的所有人全部连接到一条链子上,从链头到链尾依次试,直到出现能够解决这件事的人
- 该模式的好处
- 松耦合:责任链模式将请求的发送者和接收者解耦,使得它们可以独立地变化而互不影响。每个处理者只需要关心自己能够处理的请求,无需关心其他处理者的存在。
- 灵活性:责任链模式允许在链上动态地添加、删除或修改处理者,从而灵活地调整处理请求的顺序或逻辑。这使得系统更加灵活,能够适应不同的处理场景和需求。
- 可扩展性:责任链模式通过将处理逻辑封装在处理者类中,使得新增处理者变得相对简单。只需添加新的处理者类并将其链接到链条中,而无需修改现有的处理者类和客户端代码。
- 可维护性:责任链模式将不同处理者的处理逻辑分散到多个处理者类中,使得系统的逻辑更加清晰、简单,并且易于维护和调试。
- 动态决策:责任链模式允许处理者根据具体情况动态地决定是否处理请求,以及如何处理请求。这使得系统能够根据运行时的条件灵活地做出决策,从而实现动态的业务逻辑。
其次需要注意的是,责任链模式可能会导致请求在链条上被多次处理或没有处理,因此需要在设计时仔细考虑处理者之间的顺序和逻辑,以避免潜在的问题。在使用责任链模式时,需要根据实际情况和需求合理地设置链条,并确保每个处理者的职责和处理逻辑清晰明确。
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
代码
package AllPattern.ChainOfResponsibilityPattern;
/**
* 责任链模式
*
* @author CZJ
*/
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
//将所有对象连接起来
FuDaoYuan fuDaoYuan = new FuDaoYuan();
yuanzhang yuanzhang = new yuanzhang();
xiaozhang xiaozhang = new xiaozhang();
fuDaoYuan.nextHandler = yuanzhang;
yuanzhang.nextHandler = xiaozhang;
xiaozhang.nextHandler = null;
fuDaoYuan.HandleRequest(31);//从链头开始访问
}
}
class xiaozhang extends handler {
@Override
void HandleRequest(int i) {
if (i <= 30) {//如果当前请求当前处理者可以解决就解决
System.out.println("校长审批通过!!!");
} else {//否则的话...
if (nextHandler != null) {
nextHandler.HandleRequest(i);
} else {
System.out.println("无法审批!!!");
}
}
}
}
class yuanzhang extends handler {
@Override
void HandleRequest(int i) {
if (i <= 15) {//如果当前请求当前处理者可以解决就解决
System.out.println("院长审批通过!!!");
} else {//否则的话...
if (nextHandler != null) {
nextHandler.HandleRequest(i);
} else {
System.out.println("无法审批!!!");
}
}
}
}
class FuDaoYuan extends handler {
@Override
void HandleRequest(int i) {
if (i <= 7) {
System.out.println("辅导员审批通过!!!");
} else {
if (nextHandler != null) {
nextHandler.HandleRequest(i);
} else {
System.out.println("无法审批!!!");
}
}
}
}
//抽象的处理类
abstract class handler {
protected handler nextHandler;//类比单链表的next指针
public void setHandler(handler handler) {
this.nextHandler = handler;
}
abstract void HandleRequest(int i);
}
迭代器模式
官方定义
提供一种顺序访问聚合对象中各个元素的方法,而不需要暴露其内部结构。
UML图
个人理解
- 针对定义的理解
就比如你要遍历所有的Book对象,你不需要直到这些对象是怎么存储的,Book对象内部都有些什么,你只需要获得一个迭代器接口即可遍历其中的所有对象
- 该模式的好处
- 封装集合内部实现:迭代器模式将集合的遍历操作封装到一个独立的对象中,使得集合的内部实现对客户端代码透明,客户端不需要关心集合内部数据结构和遍历算法。这有助于提高代码的模块化和可维护性,减少了代码的耦合性。
- 统一的遍历接口:迭代器模式定义了一种统一的遍历接口,使得客户端可以一致地遍历不同类型的集合对象,包括数组、链表、树等。这样客户端不需要为不同类型的集合编写不同的遍历代码,提高了代码的重用性。
- 支持多种遍历方式:迭代器模式可以支持多种遍历方式,例如前序遍历、后序遍历、深度优先遍历、广度优先遍历等,而不需要改变集合对象的接口。这样客户端可以根据需求选择合适的遍历方式,灵活性更高。
- 简化客户端代码:使用迭代器模式可以简化客户端代码,遍历集合对象的代码通常会比手动编写遍历代码更加简洁和清晰。同时,迭代器模式可以隐藏一些遍历的复杂性,如集合的内部结构和边界处理,使得客户端代码更加简单和易于理解。
- 支持同时遍历多个集合:迭代器模式可以支持同时遍历多个集合对象,从而可以方便地进行集合之间的比较、合并、过滤等操作,提供了更多的灵活性和功能扩展性。
所以,迭代器模式具有封装集合内部实现、提供统一遍历接口、支持多种遍历方式、简化客户端代码以及支持同时遍历多个集合等好处,可以在处理集合对象时提供更加灵活、简洁和可维护的方式。
代码
package AllPattern.IteratorPattern;
import java.util.ArrayList;
import java.util.List;
public class IteratorPattern {
public static void main(String[] args) {
String[] books = new String[]{"计算机组成原理","计算机网络"};
double[] prices = new double[]{99.0,88.0};
bookAggregate bookAggregate = new bookAggregate();
for (int i = 0; i < books.length; i++) {
Book book = new Book(books[i],prices[i]);
bookAggregate.add(book);
}
Interator bookInterator = bookAggregate.createAggregate();
while (bookInterator.hasNext()){
System.out.println(bookInterator.next().toString());
}
}
}
abstract class Aggregate {
abstract Interator createAggregate();
}
class bookAggregate extends Aggregate {
List<Book> list = new ArrayList<>();
void add(Book book) {
list.add(book);
}
Book get(int index) {
return list.get(index);
}
public int getSize() {
return list.size();
}
@Override
Interator createAggregate() {
return new bookInterator(this);
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
//具体的迭代器接口,数据以及取出这些数据的方法都在xxxAggregate里
class bookInterator implements Interator {
private int index;//维护迭代器中当前元素的下标
private bookAggregate aggregate;
public bookInterator(bookAggregate bookAggregate) {
this.index = 0;
this.aggregate = bookAggregate;
}
@Override
public Boolean hasNext() {
if (index < aggregate.getSize()){
return true;
}else {
return false;
}
}
@Override
public Object next() {
Book book = aggregate.get(index);
index++;
return book;
}
}
//迭代器接口,定义判断是否有下一个元素以及取出下一个元素的抽象方法
interface Interator {
Boolean hasNext();
Object next();
}
class Book {
private String name;
private double price;
public Book(String name, Double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
中介者模式
官方定义
用一个中介对象来封装一系列对象之间的交互,从而减少对象之间的直接依赖关系。
UML图
个人理解
- 针对定义的理解
将通信的发起者与接受者通过中介者绑定起来,中介者担任一个中间媒介的作用,通信的发起者将消息发出,由中介者将消息进行转发给接受者
- 该模式的好处
- 降低系统的耦合度:中介者模式通过将系统中的多个对象之间的直接交互转变为通过中介者进行间接交互,从而降低了系统各个对象之间的耦合度。这使得系统更加灵活、可维护和可扩展,因为各个对象之间的依赖关系被集中管理,减少了对象间的相互依赖。
- 简化对象间的交互逻辑:中介者模式将系统中的复杂交互逻辑集中到中介者对象中,其他对象只需要与中介者进行简单的交互,而不需要了解其他对象的复杂内部结构和交互方式。这简化了对象间的交互逻辑,使得系统更加清晰和易于理解。
- 提高系统的灵活性和可扩展性:中介者模式可以通过增加或修改中介者对象来动态地调整系统的行为和交互方式,而不需要修改各个对象的代码。这使得系统更加灵活和可扩展,可以方便地应对需求变化或系统扩展的情况。
- 促进代码复用和维护:中介者模式将系统中共享的交互逻辑抽象到中介者对象中,从而促进了代码的复用。这样,系统中的相似交互逻辑可以集中到中介者对象中进行管理和维护,避免了代码的重复和冗余。
- 提高系统的可测试性:中介者模式通过将系统中的复杂交互逻辑集中到中介者对象中,使得系统更加可测试。因为测试只需要关注中介者对象的交互逻辑,而不需要涉及到各个对象之间的复杂交互关系,从而简化了测试的复杂性和成本。
所以,中介者模式可以降低系统的耦合度,简化对象间的交互逻辑,提高系统的灵活性和可扩展性,促进代码复用和维护,并提高系统的可测试性。这些优点使得中介者模式在复杂系统中应用广泛,并对系统的设计和开发产生了积极的影响。
代码
package AllPattern.MediatorPattern;
/**
* 中介者模式
*
* @author CZJ
*/
public class MediatorPattern {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
colleague1 colleague1 = new colleague1(mediator);
colleague2 colleague2 = new colleague2(mediator);
mediator.setColleague1(colleague1);
mediator.setColleague2(colleague2);
colleague1.sendMessage("我是同事1,我问同事2:你今天呼吸新鲜空气了吗?");
}
}
class colleague2 extends Colleague {
public colleague2(Mediator mediator) {
this.mediator = mediator;
}
//同事发送消息
void sendMessage(String message) {
mediator.sendMessage(message, this);
}
//同事响应消息
void notify(String message) {
System.out.println("同事2收到消息:" + message);
}
}
class colleague1 extends Colleague {
public colleague1(Mediator mediator) {
this.mediator = mediator;
}
//同事发送消息
void sendMessage(String message) {
mediator.sendMessage(message, this);
}
//同事响应消息
void notify(String message) {
System.out.println("同事1收到消息:" + message);
}
}
abstract class Colleague {
//同事肯定有个中介者属性,他们需要中介者进行通信间的协调
protected Mediator mediator;
}
class ConcreteMediator extends Mediator {
//具体的中介肯定有相互通信的两个同事的属性
private colleague1 colleague1;
private colleague2 colleague2;
public void setColleague1(colleague1 colleague1) {
this.colleague1 = colleague1;
}
public void setColleague2(colleague2 colleague2) {
this.colleague2 = colleague2;
}
//由具体的中介负责消息的发送
public void sendMessage(String message, Colleague colleague) {
if (colleague == colleague1) {
colleague2.notify(message); // 让同事2收到消息
} else {
colleague1.notify(message); // 让同事1收到消息
}
}
}
//中介者负责协助同事之间相互通信
abstract class Mediator {
abstract void sendMessage(String message, Colleague whoSend);
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
观察者模式
官方定义
定义一对多的依赖关系,当一个对象状态发生变化时,其依赖的对象会自动得到通知。
UML图
个人理解
- 针对定义的理解
粉丝与B站up主的订阅关系,当up主有了新的作品,该up主的所有粉丝都将会收到up主的更新提醒,无需手动发起通知
- 该模式的好处
- 解耦对象间的依赖关系:观察者模式通过使用松散耦合的方式建立对象间的依赖关系。被观察者对象(也称为主题或发布者)和观察者对象(也称为订阅者)之间不直接产生耦合,而是通过一个中介(即观察者模式中的“观察者”对象)来进行通信。这样,当被观察者对象的状态发生变化时,不会直接影响到观察者对象,从而解耦了对象之间的依赖关系,使得系统更加灵活和易于维护。
- 支持动态的一对多关系:观察者模式支持动态地添加、删除和修改观察者对象,从而实现了一对多的关系。这使得系统可以方便地适应需求变化,动态地增加或减少观察者对象,而不需要修改被观察者对象的代码。
- 提供了松耦合的通信机制:观察者模式使用松耦合的通信机制,被观察者对象和观察者对象之间通过抽象的接口进行通信,而不是直接调用彼此的方法。这样,被观察者对象和观察者对象之间的耦合度降低,使得系统更加灵活和可扩展。
- 支持广播通信:观察者模式可以实现一对多的通信方式,从而支持广播通信。当被观察者对象的状态发生变化时,所有的观察者对象都会同时接收到通知并更新,从而实现了信息的广播传递。
- 提高了系统的可维护性和可扩展性:观察者模式将对象之间的依赖关系抽象到观察者对象中,使得系统更加灵活和易于维护。当系统需要新增或修改观察者对象时,只需要针对抽象的接口进行修改,而不需要修改被观察者对象的代码,从而提高了系统的可维护性和可扩展性。
所以,观察者模式具有解耦对象间的依赖关系、支持动态的一对多关系、提供了松耦合的通信机制、支持广播通信以及提高系统的可维护性和可扩展性等好处。通过使用观察者模式,可以使系统的设计更加灵活、可扩展和易于维护,同时也有助于降低对象之间的耦合度,提高系统的可维护性和可复用性。
代码
package AllPattern.ObserverPattern;
import com.sun.corba.se.spi.transport.ReadTimeouts;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
/**
* 观察者模式
*
* @author CZJ
*/
public class ObserverPattern {
public static void main(String[] args) {
Subject subject = new concreteSubject("目标A");
Observer observer = new ConcreteObserver("张三",subject);
Observer observer1 = new ConcreteObserver("李四",subject);
Observer observer2 = new ConcreteObserver("王五",subject);
subject.setState("更新了");
System.out.println("************************");
subject.setState("未更新");
}
}
class concreteSubject implements Subject {
public String name;//up主名字
public String state;//up主当前状态
public List<Observer> list;//up主的所有粉丝列表
public concreteSubject(String name){//初始化的时候需要定义目标的名字以及当前状态,并生成观察者数组
this.name = name;
state = "未更新";
list = new ArrayList<>();
}
@Override
public void add(Observer observer) {//为目标添加一个观察者
list.add(observer);
}
@Override
public void delete(Observer observer) {//为目标删除一个观察者
list.remove(observer);
}
@Override
public void Notify() {//更新up主的每个粉丝的状态,是在up主更新过后使用的
for (Observer observer:list){
observer.Update();
}
}
@Override
public void setState(String state) {//up主发生更新
this.state = state;
System.out.println(name + "的状态发生变化,当前状态为:" + state);
Notify();//通知该up主的所有粉丝
}
@Override
public String getState() {//获取当前目标的状态
return state;
}
}
interface Subject {//up主
void add(Observer observer);//up主添加一个粉丝
void delete(Observer observer);//up主删除一个粉丝
void Notify();//up主通知粉丝更新
void setState(String state);//up主设置自己当前状态
String getState();//up主获取当前自己的状态
}
class ConcreteObserver extends Observer {
private String name;//粉丝的名字
private String state;//粉丝观察的up主的当前状态
private Subject subject;//粉丝观察的哪个up主
public ConcreteObserver(String name,Subject subject) {
this.name = name;
this.subject = subject;
subject.add(this);
state = subject.getState();//获取up主的当前状态
}
@Override
void Update() {
System.out.println(name + "已经收到通知了");
state = subject.getState();
System.out.println(name + "改变后状态为:" + state);
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
abstract class Observer {
abstract void Update();//粉丝进行状态更新,接受up主的更新通知
}
备忘录模式
官方定义
在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
UML图
个人理解
- 针对定义的理解
类似于市面上一些备份软件,可以将按照时间点进行数据的备份,并在恢复的时候可以指定某一时间点进行恢复,也好比 Linux 中的快照功能
- 该模式的好处
- 对象状态的保存和恢复:备忘录模式可以将对象的状态保存到备忘录对象中,从而在需要时可以轻松地恢复到先前的状态。这对于需要实现撤销、恢复、版本控制等功能的系统非常有用。
- 封装性的保护:备忘录模式通过将对象的状态保存在备忘录对象中,可以保护对象的封装性。发起人对象不需要暴露其内部状态给外部,只需通过备忘录对象进行状态的保存和恢复。
- 灵活性和扩展性:备忘录模式可以在不修改对象的情况下,灵活地保存和恢复对象的状态。这使得系统更加灵活和可扩展,可以随时添加新的备忘录对象来保存不同版本的状态。
- 简化原发器对象:备忘录模式可以将对象的状态保存在备忘录对象中,从而使得原发器对象的职责更加清晰和简化。原发器对象只需要关注自身的核心业务逻辑,状态的保存和恢复由备忘录对象负责。
- 支持多状态的保存和恢复:备忘录模式可以支持多个状态的保存和恢复,每个备忘录对象可以保存不同的状态信息。这对于需要多状态保存和恢复的系统非常有用,例如多层撤销和恢复操作等场景。
总的来说,备忘录模式可以提供一种灵活、可扩展和封装性良好的方式来保存和恢复对象的状态,从而增加系统的可维护性、灵活性和扩展性。
代码
package AllPattern.MementoPattern;
import java.util.ArrayList;
import java.util.List;
/**
* 备忘录模式
*
* @author CZJ
*/
public class MementoPattern {
public static void main(String[] args) {
creakMaker creakMaker = new creakMaker();
Originator originator = new Originator();
originator.setState(1024);
Memento memento1 = originator.createMemento();//创建第一次备份
creakMaker.addMemento(memento1);
originator.setState(2048);
Memento memento2 = originator.createMemento();//创建第二次备份
creakMaker.addMemento(memento2);
originator.setState(4096);
Memento memento3 = originator.createMemento();//创建第三次备份
creakMaker.addMemento(memento3);
System.out.println("当前备份状态:" + originator.getState());
System.out.println("该管理者管理的所有状态:\n");
creakMaker.showAllMemento();
Memento memento = creakMaker.getMemento(2);
originator.setMemento(memento);
System.out.println("备份被还原到了状态" + originator.getState());
}
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
class Memento {
private int state;
public int getState() {
return state;
}
public Memento(int state) {
this.state = state;
}
// public void setState(int state){
// this.state = state;
// }
}
//原发器,用来创建备忘录的
class Originator {
private int state;//必须要有状态属性,通过该状态确定创建的备忘录的状态,也可以使用传递状态参数的方式
public void setState(int state) {
this.state = state;
}
public int getState() {
return state;
}
public Memento createMemento() {
return new Memento(state);
}
public void setMemento(Memento memento) {//根据某次备忘录进行还原,还原效果是通过Originator中的state属性体现的
state = memento.getState();
}
}
class creakMaker {
List<Memento> list = new ArrayList<>();//存储备份历史记录
public void addMemento(Memento memento) {//添加一个备份
list.add(memento);
}
public Memento getMemento(int index) {//获取某次备份
if (index >= 1 && index <= list.size()) {
return list.get(index - 1);
}
return null;
}
public void showAllMemento() {//展示当前管理者管理的所有备份
int cnt = 1;
for (Memento memento : list) {
System.out.println("第" + cnt + "次备份," + "状态为:" + memento.getState());
}
}
}
状态模式
官方定义
用于在对象内部封装状态,并在状态发生变化时改变对象的行为
UML图
个人理解
- 针对定义的理解
类比贩卖机与人从贩卖机购买饮料,stateA
是余货充足可以成功购买的状态,stateB
则是余货不足需要补货的状态,将余货的充足与不足各封装成了一种状态并切入对象(context类,也就是贩卖机)中,这样使得从贩卖机购买饮料后将会选择对应的状态进行饮料购买后的处理行为
- 该模式的好处
- 将状态的切换与具体行为的实现解耦:状态模式将对象的状态与其行为进行分离,使得状态的切换可以独立于具体的行为。这样,在系统需要改变状态时,只需要改变状态对象,而无需修改上下文对象的代码,从而实现了状态的灵活变更。
- 简化复杂的条件语句:在传统的条件语句中,当对象的状态较多且复杂时,会导致条件语句的嵌套层级增加,代码变得难以理解和维护。而状态模式通过将状态的行为封装到具体状态类中,避免了复杂的条件语句,使得代码更加清晰和易于理解。
- 提高系统的灵活性和可扩展性:状态模式允许在运行时动态地改变对象的状态,从而可以根据需求增加新的状态或修改现有的状态,而无需修改上下文对象的代码。这样,系统变得更加灵活和可扩展,可以方便地应对不同的需求变化。
- 符合开闭原则:状态模式将状态的实现封装到具体状态类中,新增状态时只需要添加新的具体状态类,不需要修改上下文对象的代码。这符合开闭原则,即对扩展开放,对修改关闭,使得系统更加稳定和易于维护。
- 提高代码的重用性:状态模式将状态相关的代码封装到具体状态类中,可以提高代码的重用性。不同的对象可以共享相同的状态对象,从而减少代码的重复。
- 提供了清晰的状态转移逻辑:状态模式通过将状态的行为封装到具体状态类中,使得状态的转移逻辑变得清晰可见。状态的转移逻辑集中在具体状态类中,便于管理和维护。
代码
package AllPattern.StatePattern;
/**
* 状态模式
*/
public class StatePattern {
public static void main(String[] args) {
Context context = new Context();
context.request();
context.request();
context.request();
context.request();
context.request();
System.out.println("当前余量:" + context.getCount());
}
}
class stateB implements State{
@Override
public void Handle(Context context) {
int count = context.getCount();
if (count == 0){
System.out.println("购买失败,请等待补货!!!");
context.setCount(10);//进行补货
System.out.println("补货成功,请重新购买");
context.setState(new stateA());//既然补货成功,则需要更换状态为stateA
}
}
}
//余货充足
class stateA implements State{
@Override
public void Handle(Context context) {
int count = context.getCount();//获取饮料瓶数
if (count >= 1){
System.out.println("购买成功!!!");
context.setCount(count - 1);
if (context.getCount() == 0){//如果买完一瓶饮料后没有余量了,则要将状态赋值成缺货状态
context.setState(new stateB());
}
}else {
System.out.println("购买失败");
}
}
}
interface State{
void Handle(Context context);//处理方法
}
//客户感兴趣的接口,这里比作贩卖机
class Context{
private int count;//当前贩卖机的饮料余量
private State state;//当前接口对应的状态
public Context(){
count = 3;
state = new stateA();//刚创建的贩卖机的余量一定是正常的,所以赋予状态A
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void request(){
state.Handle(this);//如果是stateA,则是在余量正常的情况下买一瓶饮料,如果是stateB,则是在余量不充足的情况下买一瓶饮料
//但是要说明在哪个贩卖机上买,所以需要传递context对象
}
}
策略模式
官方定义
定义一系列算法,将其封装成对象,并使其可以互换使用。
UML图
个人理解
- 针对定义的理解
就是将复杂的算法封装成一个对象,当调用算法是只需要传递算法需要的参数,具体算法的内部逻辑无需用户知道
- 该模式的好处
- 可扩展性:策略模式允许在不修改原有代码的情况下,动态地添加新的策略或修改现有策略。这使得系统更加灵活和可扩展,可以随时适应变化的需求。
- 可维护性:策略模式将不同的策略逻辑封装到独立的策略类中,使得代码更加模块化和易于维护。当需要修改某个策略时,不会影响到其他策略的实现。
- 可替代性:策略模式通过定义共同的接口或抽象类来实现不同策略的替代性。这意味着可以轻松地切换不同的策略,以满足不同的业务需求,而不需要修改客户端代码。
- 解耦合:策略模式将策略的实现从客户端代码中解耦出来,使得客户端只需要关注选择和使用不同的策略,而不需要关心具体策略的实现细节。这可以减少类之间的依赖关系,提高系统的灵活性和可维护性。
- 更好的可读性:策略模式将不同策略的实现逻辑分离到独立的类中,使得代码更加清晰和易于理解。不同的策略可以通过类名或者注释等方式进行标识,提高了代码的可读性。
总的来说,策略模式通过将不同的策略封装成独立的类,并使用共同的接口或抽象类进行统一管理,实现了高度的灵活性、可维护性、可扩展性和解耦合,是一种强大的设计模式。
代码
package AllPattern.StrategyPattern;
/**
* 策略模式——个人认为最简单的模式
* @author CZJ
*/
public class StrategyPattern {
public static void main(String[] args) {
Strategy strategy = new addAlgorithm();//加法算法
Context context = new Context(strategy);
int result = context.getResult(15, 30);
System.out.println("结果为:" + result);
Strategy strategy1 = new chenAlgorithm();//乘法算法
Context context1 = new Context(strategy1);
int result1 = context1.getResult(15, 30);
System.out.println("结果为:" + result1);
}
}
class Context{
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int getResult(int a, int b){
return strategy.AlgorithmInterface(a,b);
}
}
class chenAlgorithm implements Strategy{
@Override
public int AlgorithmInterface(int a, int b) {
return a * b;
}
}
class jianAlgorithm implements Strategy{
@Override
public int AlgorithmInterface(int a, int b) {
return a - b;
}
}
class addAlgorithm implements Strategy{
@Override
public int AlgorithmInterface(int a, int b) {
return a + b;
}
}
interface Strategy{
int AlgorithmInterface(int a,int b);//具体的算法实现
}
访问者模式
官方定义
是一种操作一组对象的操作,它的目的是不改变对象的定义,但允许新增不同的访问者,来定义新的操作。
UML图
个人理解
- 针对定义的理解
假设有一个图书馆,里面有各种不同类型的书籍,如小说、科技、历史、文学等。现在需要对这些书籍进行一些操作,如借阅、归还、维护状态等。传统的做法是在每个书籍类中添加这些操作的方法,但这样会导致书籍类的修改频繁和代码臃肿。而使用访问者模式,可以将这些操作封装到不同的访问者类中,实现了操作的解耦和复用。
- 该模式的好处
- 解耦元素对象和操作:访问者模式将元素对象和操作进行了解耦,使得操作可以独立于元素对象的类进行变化和扩展。元素对象只需要提供一个接受访问者对象的方法,而不需要关注具体的操作逻辑,从而降低了元素对象的复杂性。
- 增加新的操作方便:通过引入访问者对象,新增加一个操作只需要添加一个新的访问者类,而不需要修改元素对象的类。这符合开闭原则,使得系统的可维护性和扩展性得到了提高。
- 集中管理操作逻辑:访问者模式将操作逻辑集中在访问者类中,使得系统中的各种操作可以在一个地方进行管理和修改,不需要分散到各个元素对象的类中,从而提高了代码的可维护性。
- 支持对复杂对象结构的处理:访问者模式适用于处理复杂的对象结构,其中包含多种类型的元素对象。通过访问者模式,可以在不修改元素对象的情况下,对复杂的对象结构进行遍历和操作。
- 可扩展性强:访问者模式的结构灵活,可以方便地增加新的元素对象和操作,而不需要修改现有的代码,从而具有较强的扩展性。
- 分离关注点:访问者模式将不同的操作逻辑封装在访问者类中,使得每个访问者类只关注一个具体的操作,从而提高了代码的清晰性和可读性。
因此,访问者模式在处理复杂对象结构和多种操作时具有很多的好处,可以提高系统的灵活性、可维护性和扩展性,同时分离关注点,使得代码更加清晰和可读。
代码
package AllPattern.VisitorPattern;
import java.util.ArrayList;
import java.util.List;
/**
* 访问者模式
* @author CZJ
*/
public class VisitorPattern {
public static void main(String[] args) {
ObjectStructure objectStructure = new ObjectStructure();
Vistor1 vistor = new Vistor1();
objectStructure.Accept(vistor);//该访问者依次访问示例数据中的所有人
System.out.println("访问者1的最长工作年限:" + vistor.getMaxWorkYear() + ",访问者1的最高分数:" + vistor.getMaxScore());
}
}
class ObjectStructure {
List<person> personList = new ArrayList<>();
public ObjectStructure() {//定义一些示例数据
personList.add(new Teacher("教师1", 30, 3));
personList.add(new Teacher("教师2", 60, 10));
personList.add(new Teacher("教师3", 90, 9));
personList.add(new Student("学生1", 10, 79));
personList.add(new Student("学生2", 15, 94));
personList.add(new Student("学生3", 20, 99));
}
public void Accept(Vistor vistor) {//测试某个访问者Visitor逐个去访问personList中的对象
for (person person : personList) {
person.accept(vistor);
}
}
}
class Vistor1 implements Vistor {
private int maxScore = -1;
private int maxWorkYear = -1;
public int getMaxScore() {//求出学生中的最高分数
return maxScore;
}
public int getMaxWorkYear(){//求出老师中工作的最长年限
return maxWorkYear;
}
@Override
public void visitTeacher(Teacher teacher) {//具体实现应该如何访问这个老师
System.out.println("Vistor1访问了老师:" + teacher.getName() + ",工龄:" + teacher.getWorkYear());
maxWorkYear = Math.max(teacher.getWorkYear(),maxWorkYear);//访问某个对象的同时可以实现基于该对象的一个或者多个操作
}
@Override
public void visitStudent(Student student) {
System.out.println("Visitor1访问了学生:" + student.getName() + ",成绩:" + student.getScore());
maxScore = Math.max(student.getScore(),maxScore);
}
}
interface Vistor {//访问者接口应该包含他可能访问的所有类型的对象,比如在这里这个访问者可能访问的对象是老师和学生
void visitTeacher(Teacher teacher);
void visitStudent(Student student);
}
class Teacher extends person {
private int workYear;
public Teacher(String name, int age, int workYear) {
super(name, age);
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
@Override
public void accept(Vistor vistor) {//访问者visitor访问一个老师
vistor.visitTeacher(this);
}
}
class Student extends person {
private int score;
public Student(String name, int age, int score) {
super(name, age);
this.score = score;
}
public int getScore() {
return score;
}
@Override
public void accept(Vistor vistor) {
vistor.visitStudent(this);//访问者visitor访问一个学生
}
}
abstract class person {
private String name;
private int age;
public person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
abstract public void accept(Vistor vistor);//该人接受来自visitor的访问
}
行为型类类型
模板方法模式
官方定义
定义一个算法的框架,将其中某些步骤的实现延迟到子类。
UML图
个人理解
- 针对定义的理解
就是将相同的行为封装到一个模板中,不同的对象都会产生这些行为,不同的对象只需要调用这个方法即可完成通用操作,对象只需考虑自己的个性化操作并将其添加在通用操作的附近即可
- 该模式的好处
- 提供模板化的算法框架:模板方法模式通过将算法的框架和骨架固定在抽象类中,将具体的实现细节交由子类去实现,从而提供了一个模板化的算法框架。这样可以避免重复的代码,提高代码的复用性和可维护性。
- 提供了一种扩展点:模板方法模式在抽象类中定义了一些可选的步骤或者扩展点,子类可以根据需要选择性地进行实现或者扩展。这样可以在不修改抽象类的情况下,通过子类的扩展来改变算法的行为。
- 符合开闭原则:模板方法模式将算法的框架和骨架固定在抽象类中,使得算法的变化可以通过子类的扩展来实现,而不需要修改抽象类的代码。这符合开闭原则,即对扩展开放,对修改关闭,提高了系统的可维护性和扩展性。
- 提供了一种钩子(Hook)机制:模板方法模式在抽象类中可以定义一些默认的实现,子类可以根据需要选择性地进行重写。这样可以在不影响整体算法的情况下,对某些步骤进行定制化的处理,从而满足特定的业务需求。
- 简化客户端的使用:模板方法模式将算法的实现细节封装在抽象类中,客户端只需要关注抽象类和具体子类的调用,不需要关心具体的实现细节。这样可以简化客户端的使用,降低了客户端的复杂性。
- 提高代码的可维护性和可读性:模板方法模式将算法的框架和骨架固定在抽象类中,将具体的实现细节交由子类去实现,使得代码结构更加清晰和易于理解。同时,模板方法模式可以避免重复的代码,提高了代码的可维护性和可读性。
所以,模板方法模式在提供模板化的算法框架、提供扩展点、符合开闭原则、提供钩子机制、简化客户端使用以及提高代码的可维护性和可读性等方面具有很多的好处。
代码
package AllPattern.TemplateMethodPattern;
/**
* 模板方法模式
* @author CZJ
*/
public class TemplateMethodPattern {
public static void main(String[] args) {
teacher teacher = new teacher();
student student = new student();
teacher.TemplateMethod();
System.out.println("-------------------");
student.TemplateMethod();
}
}
class teacher extends person{
@Override
void Operition1() {
System.out.println("老师:上课 讲课 解答问题 布置作业");
}
@Override
void Operition2() {
System.out.println("老师:批改作业 打分数");
}
}
class student extends person{
@Override
void Operition1() {
System.out.println("学生:听课 学习 做笔记 提出问题");
}
@Override
void Operition2() {
System.out.println("学生:写作业 提交作业");
}
}
abstract class person{
public void TemplateMethod(){//模板方法中存储的则是通用操作
System.out.println("上课,去教室");//学生和老师都有 上课,去教室 这步操作
Operition1();
System.out.println("下课,离开教室");//学生和老师都有 下课,离开教室 这步操作
Operition2();
}
abstract void Operition1();//Operition1 和 Operition2 是不同的对象所具有的原语操作呢
abstract void Operition2();
}
版权声明:本文为CSDN博主「憋废话_开码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43683622/article/details/130119481
解释器模式
官方定义
定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的“语言”是指使用规定格式和语法的代码
UML图
个人理解
- 针对定义的理解
就是输入一段话,我需要这段话中的格式按照我想要的来,不能毫无章法,context
中存放着你想要的规则,等会待检测的句子必须是这里面的规则中出现的才行,NonTerminalExpress
用来将待检测的句子分开,然后调用TerminalExpress
中的方法进行检测,检测这些被分开的成分是否是我想要的格式规则(context
中存放的)
这个模式大家看看就好,我自己理解的也不是很透彻,后面如果博主有了新的理解在完善吧!
- 该模式的好处
- 灵活性:解释器模式允许在运行时动态地定义、解析和执行语言或表达式。这使得系统更加灵活,可以根据需要动态地修改语言规则或表达式,而无需修改代码。
- 可扩展性:解释器模式通过使用抽象语法树来表示语言或表达式,使得新增语言规则或表达式变得相对简单。只需添加新的解释器类来处理新的语言规则或表达式,而无需修改现有的解释器类。
- 可维护性:解释器模式将复杂的语言或表达式的解析逻辑分散到多个解释器类中,使得系统的逻辑更加清晰、简单,并且易于维护和调试。
- 可重用性:解释器模式通过将语言或表达式的解析逻辑封装在解释器类中,使得这些解释器可以被多个客户端重用,从而提高了代码的复用性。
- 独立性:解释器模式将语言或表达式的解析逻辑独立于其他业务逻辑,使得系统的不同部分可以独立地演化和改变,而不会相互影响。
其次,解释器模式在处理复杂语言或表达式时比较适用,对于简单的情况可能会显得过于复杂。在使用解释器模式时,需要权衡好灵活性和复杂性之间的关系,选择合适的设计方案。
代码
package AllPattern.InterpreterPattern;
import java.util.HashSet;
import java.util.Set;
/**
* @author CZJ
*/
public class InterpreterPattern {
public static void main(String[] args) {
Context context = new Context();
context.check("A区的开发人员");
context.check("B区的调试人员");
context.check("C区的测试人员");
System.out.println("==========");
context.check("D区的程序员");
context.check("D区的测试员");
context.check("A区的程序员");
}
}
class NonTerminalExpress extends Expression {
private TerminalExpress regions;
private TerminalExpress person;
public NonTerminalExpress(TerminalExpress region, TerminalExpress person) {
this.regions = region;
this.person = person;
}
@Override
boolean Interpret(String info) {
String[] data = info.split("的");
return regions.Interpret(data[0]) && person.Interpret(data[1]);
}
}
class TerminalExpress extends Expression {
private Set<String> set = new HashSet<>();
public TerminalExpress(String[] data) {
// for (遍历对象类型 对象名 : 遍历对象)
for (String str : data) {
set.add(str);
}
}
public boolean Interpret(String info) {
return set.contains(info);
}
}
class Context {
//想要的文法规则
private String[] regions = {"A区", "B区", "C区"};
private String[] persons = {"开发人员", "测试人员", "调试人员"};
private NonTerminalExpress nonterminal;
public Context() {
TerminalExpress region = new TerminalExpress(regions);
TerminalExpress person = new TerminalExpress(persons);
nonterminal = new NonTerminalExpress(region, person);
}
public void check(String info) {
boolean bool = nonterminal.Interpret(info);![在这里插入图片描述](https://img-blog.csdnimg.cn/abeddfdff0d54d6ea215b0559d7cb5d1.jpeg#pic_center)
if (bool) {
System.out.println("识别成功");
} else {
System.out.println("识别失败");
}
}
}
abstract class Expression {
//解释方法
abstract boolean Interpret(String info);
}
“Hello World,Hello Challenge!”