目录
设计模式是什么
- 设计模式,是一种被反复使用的、经过多次实践验证的、被公认为优秀的解决特定问题的代码设计经验的总结。它为软件开发人员提供了一种通用的解决方案,可以用来解决在软件开发过程中经常遇到的一些常见问题。设计模式使得代码更加灵活、可复用、易于维护和扩展。
设计模式的作用
-
提高代码的可读性和可维护性:设计模式可以使代码更加清晰、易于阅读和理解,降低代码出错的风险,也方便后期的维护和更新。
-
提高代码的复用性和可扩展性:设计模式可以将代码中的通用部分抽象出来,形成独立的模块,方便在不同的场景中复用。同时,设计模式也可以使得代码更加灵活,方便后期的扩展和修改。
-
提高软件开发效率:设计模式为开发人员提供了一种通用的解决方案,避免了重复地处理相似的问题,从而提高了软件开发的效率。
-
提高软件系统的稳定性和可靠性:设计模式经过多次实践验证,是被公认为优秀的解决方案,使用设计模式可以降低软件系统出错的风险,提高系统的稳定性和可靠性。
设计模式分类
![设计模式](https://i-blog.csdnimg.cn/blog_migrate/0bc19d1e3052da64ae408241f5f0baee.jpeg)
-
创建型模式:用于创建对象的模式,包括单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式等。
-
结构型模式:用于处理类或对象的组合关系的模式,包括适配器模式、桥接模式、装饰器模式、组合模式、外观模式、享元模式和代理模式等。
-
行为型模式:用于描述对象之间的通信方式和责任分配的模式,包括模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式和状态模式等。
此外,还有一些其他类型的设计模式,如并发型模式、分布式模式等。
设计模式的六大原则
-
单一职责原则(SRP):一个类只负责一个职责,避免出现一个类承担过多的职责,导致代码难以维护和修改。
-
开放封闭原则(OCP):对扩展开放,对修改封闭,通过抽象化和多态等技术实现。
-
里氏替换原则(LSP):子类可以替换父类出现在任何地方,保证程序的正确性。
-
依赖倒置原则(DIP):高层模块不应该依赖低层模块,二者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象。
-
接口隔离原则(ISP):客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。
-
迪米特法则(LoD):一个对象应该对其他对象保持最少的了解,即最少知道原则,降低耦合度,使系统更加灵活、可扩展和易于维护。
单例模式
1.单例模式是什么
- 单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。这意味着在整个应用程序中,只有一个对象实例被创建,并且所有对该对象的请求都将返回相同的实例。
2.单例模式的应用
-
管理共享资源:单例模式可以用来管理某些共享资源,例如数据库连接池、线程池等,确保在整个应用程序中只有一个资源实例被创建和共享。
-
配置信息管理:单例模式可以用来管理应用程序的配置信息,例如日志配置、系统参数等。
-
状态管理:单例模式可以用来管理应用程序的状态信息,例如用户登录状态、购物车状态等。
-
工具类库:单例模式可以用来实现一些工具类库,例如日志工具、缓存工具等。
3.单例模式的优缺点
单例模式的优点:
-
保证了系统内部只有一个实例,节省了系统资源,提高了系统性能。
-
提供了一个全局访问点,方便了对该实例的访问和管理。
-
由于单例模式只有一个实例,因此可以控制实例的生成和数量,避免了系统中出现过多的相似对象导致的混乱。
单例模式的缺点:
-
单例模式的扩展性不好,如果需要扩展单例模式,可能需要修改代码,增加代码复杂度。
-
单例模式对代码的测试不利,因为单例模式很难被模拟和替换。
-
单例模式容易引起全局变量的滥用,从而导致代码的不可预测性和不稳定性。
-
单例模式可能会对代码的可维护性造成影响,因为单例模式隐藏了其内部实现细节,使得代码难以理解和修改。
4.单例模式使用注意事项:
-
线程安全:如果在多线程环境下使用单例模式,需要保证其线程安全性。可以使用双重检查锁定等方式来实现线程安全的单例模式。
-
序列化和反序列化:如果需要对单例对象进行序列化和反序列化,需要为单例类提供一个readResolve方法,否则可能会导致多个实例被创建。
-
类加载器:如果使用不同的类加载器加载单例类,可能会导致多个实例被创建。可以使用静态内部类的方式来解决这个问题。
-
单例对象的生命周期:单例对象的生命周期应该与应用程序的生命周期一致,否则可能会导致单例对象无法被正确地管理和回收。
-
单例模式的滥用:单例模式虽然有很多优点,但也容易被滥用。在使用单例模式时需要慎重考虑,避免对代码的可测试性、可维护性和扩展性造成影响。
5.单例的创建方式
常见的单例创建方式包括:
-
饿汉式:在类加载时就创建单例对象,线程安全,但可能会浪费资源。示例代码:
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
这种方式在类加载时就创建了单例对象,因此线程安全,但可能会浪费一些内存空间。
-
懒汉式:在第一次使用时才创建单例对象,节省资源,但需要考虑线程安全问题。示例代码:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种方式在第一次使用时才创建单例对象,避免了浪费内存空间,但需要考虑线程安全问题。
3.双重检查锁:在懒汉式的基础上增加了双重检查,提高了并发性能。示例代码:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
这种方式在第一次使用时才创建单例对象,同时通过双重检查锁定来保证线程安全。需要注意的是,需要将instance声明为volatile类型,以保证可见性。
工厂模式
1.工厂模式是什么
- 工厂模式是一种创建型设计模式,它提供了一种创建对象的方式,而无需暴露对象创建的逻辑。通过工厂模式,客户端可以通过调用工厂类的方法来创建对象,而不需要知道具体的实现细节。
- 工厂模式通常包括一个抽象工厂类和多个具体工厂类。抽象工厂类定义了一个工厂方法,用于创建产品对象,具体工厂类实现了工厂方法,用于创建具体的产品对象。客户端通过调用具体工厂类的方法来创建产品对象。
2.工厂模式的好处
- 将对象的创建与使用分离,提高了系统的灵活性和可维护性。
- 通过工厂方法,可以对对象的创建进行统一管理和控制,从而确保对象的一致性和正确性。
- 可以通过工厂方法对对象进行缓存,提高系统的性能和效率。
- 工厂模式可以隐藏对象的创建细节,使得客户端只需要关注对象的使用,降低了客户端的复杂度。
- 工厂模式可以根据不同的需求创建不同的对象,提高系统的扩展性和可定制性。
- 工厂模式可以将对象的创建和使用解耦,方便进行单元测试和调试。
3.Spring开发框架中的工厂设计模式
1.Spring IOC
-
BeanFactory和ApplicationContext:Spring框架中的BeanFactory和ApplicationContext就是工厂模式的具体实现。它们都是用来创建和管理Bean对象的工厂,将Bean的创建和使用进行了分离,提高了系统的灵活性和可维护性。
-
工厂方法模式:Spring框架中还广泛使用了工厂方法模式。例如,通过使用FactoryBean接口,可以自定义Bean的创建过程,从而实现更加灵活的对象创建方式。此外,在Spring中还有一些常用的工厂方法,例如MessageSource、ResourceLoader等,它们都是通过工厂方法来创建对象的。
2.为什么Spring IOC要使用工厂设计模式创建Bean呢
-
Spring IOC容器负责创建和管理Bean对象,通过工厂方法将Bean的创建和使用进行了解耦。这样,系统可以更加灵活地处理对象的创建和销毁,同时也方便进行单元测试和调试。此外,Spring IOC容器还支持对象的依赖注入,可以自动将对象之间的依赖关系注入到对象中,从而进一步提高了系统的可维护性和扩展性。
4.工厂模式分类
-
简单工厂模式:也称为静态工厂模式,是工厂模式中最简单的一种形式。简单工厂模式通过一个静态方法来创建对象,客户端只需要传入相应的参数,就可以获得所需的对象。示例代码:
public class SimpleFactory {
public static Product createProduct(String type) {
if (type.equals("A")) {
return new ConcreteProductA();
} else if (type.equals("B")) {
return new ConcreteProductB();
} else {
throw new IllegalArgumentException("Invalid product type: " + type);
}
}
}
public interface Product {
void doSomething();
}
public class ConcreteProductA implements Product {
@Override
public void doSomething() {
System.out.println("Product A is doing something.");
}
}
public class ConcreteProductB implements Product {
@Override
public void doSomething() {
System.out.println("Product B is doing something.");
}
}
// Usage:
Product productA = SimpleFactory.createProduct("A");
productA.doSomething();
Product productB = SimpleFactory.createProduct("B");
productB.doSomething();
-
工厂方法模式:也称为多态性工厂模式,是工厂模式的一种常见形式。工厂方法模式通过定义一个抽象工厂接口和多个具体工厂类来创建对象,客户端通过调用工厂方法来获取所需的对象。示例代码:
public interface Factory {
Product createProduct();
}
public class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
public class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// Usage:
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.doSomething();
Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.doSomething();
-
抽象工厂模式:也称为Kit模式,是工厂模式中最复杂的一种形式。抽象工厂模式通过定义一个抽象工厂接口和多个具体工厂类来创建一组相关或相互依赖的对象,客户端通过调用工厂方法来获取所需的对象。示例代码:
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
public interface ProductA {
void doSomething();
}
public interface ProductB {
void doSomething();
}
public class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
public class ConcreteProductA1 implements ProductA {
@Override
public void doSomething() {
System.out.println("Concrete product A1 is doing something.");
}
}
public class ConcreteProductA2 implements ProductA {
@Override
public void doSomething() {
System.out.println("Concrete product A2 is doing something.");
}
}
public class ConcreteProductB1 implements ProductB {
@Override
public void doSomething() {
System.out.println("Concrete product B1 is doing something.");
}
}
public class ConcreteProductB2 implements ProductB {
@Override
public void doSomething() {
System.out.println("Concrete product B2 is doing something.");
}
}
// Usage:
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
productA1.doSomething();
AbstractFactory factory2 = new ConcreteFactory2();
ProductB productB2 = factory2.createProductB();
productB2.doSomething();
在这个示例中,抽象工厂类定义了创建一组相关产品的接口。具体工厂类实现了这些接口并创建了具体的产品。每个具体产品都实现了抽象产品类所定义的方法。客户端代码使用抽象工厂对象来创建一组相关的产品。
代理模式
1.代理模式是什么
-
代理模式是一种结构型设计模式,它允许你提供一个代理对象来控制对其他对象的访问。
-
代理模式有多种类型,包括静态代理、动态代理。静态代理是在编译时创建的代理对象,而动态代理是在运行时创建的代理对象。
2.代理模式应用场景
- Spring AOP、日志打印、异常处理、事务控制、权限控制等
3.Java代理模式的分类
- 静态代理(静态定义代理类)
- 动态代理(动态生成代理类,也称为Jdk自带动态代理)
- Cglib 、javaassist(字节码操作库)
静态代理
静态代理是一种在编译时就确定代理对象的方式。在静态代理中,需要为每个目标对象创建一个代理对象,并将客户端请求转发给目标对象。静态代理通常使用接口来定义代理和目标对象之间的公共方法。
以下是一个简单的静态代理示例:
public interface Subject {
void doSomething();
}
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("Real subject is doing something.");
}
}
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void doSomething() {
System.out.println("Proxy subject is doing something before real subject.");
realSubject.doSomething();
System.out.println("Proxy subject is doing something after real subject.");
}
}
// Usage:
RealSubject realSubject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(realSubject);
proxySubject.doSomething();
这段代码中,RealSubject是真实主题类,实现了Subject接口,它的doSomething()方法是真正要执行的业务逻辑。ProxySubject是代理主题类,也实现了Subject接口,它在调用真实主题类的doSomething()方法之前和之后都可以添加额外的逻辑。在使用时,先创建一个RealSubject对象,再将它作为参数传递给ProxySubject的构造函数创建一个代理对象。最后,通过代理对象调用doSomething()方法即可。
动态代理
动态代理是一种在运行时创建代理对象的方式。在动态代理中,可以使用 Java 的反射机制来创建代理对象,并将客户端请求转发给目标对象。动态代理通常使用接口来定义代理和目标对象之间的公共方法。
以下是一个简单的动态代理示例:
public interface Subject {
void doSomething();
}
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("Real subject is doing something.");
}
}
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Dynamic proxy is doing something before real subject.");
Object result = method.invoke(target, args);
System.out.println("Dynamic proxy is doing something after real subject.");
return result;
}
}
// Usage:
RealSubject realSubject = new RealSubject();
DynamicProxy dynamicProxy = new DynamicProxy(realSubject);
Subject subjectProxy = (Subject) Proxy.newProxyInstance(
RealSubject.class.getClassLoader(),
RealSubject.class.getInterfaces(),
dynamicProxy
);
subjectProxy.doSomething();
这段代码中,RealSubject是真实主题类,实现了Subject接口,它的doSomething()方法是真正要执行的业务逻辑。DynamicProxy是动态代理类,实现了InvocationHandler接口,它在调用真实主题类的doSomething()方法之前和之后都可以添加额外的逻辑。在使用时,先创建一个RealSubject对象,再创建一个DynamicProxy对象,并将RealSubject对象传递给它。最后,通过调用Proxy.newProxyInstance()方法创建代理对象,该方法接收三个参数:ClassLoader对象、代理对象要实现的接口数组和InvocationHandler对象。最终返回的代理对象也是实现了Subject接口的对象,它的doSomething()方法会被动态代理类所拦截,从而在执行真实主题类的doSomething()方法之前和之后添加额外的逻辑。
建造者模式
1.建造者模式是什么
-
建造者模式是一种创建型设计模式,它允许您创建复杂对象的不同部分,并在使用这些部分来构建完整对象时将它们组装在一起。建造者模式将对象的构造过程与其表示分离,可以更加灵活和可扩展地创建对象。
建造者模式包含的角色:
- 产品类:表示要构建的复杂对象,通常由多个部分组成。
- 抽象建造者类:定义了构建产品所需的所有方法,并声明了一个返回构建后产品的方法。
- 具体建造者类:实现了抽象建造者类中定义的所有方法,并且能够返回一个构建后的产品。
- 指挥者类:控制构建过程,通常包含一个抽象建造者类的引用,客户端通常只需要与指挥者类进行交互。
2.建造者模式的使用场景
使用场景:
- 建造者模式通常用于创建复杂的对象 , 其中对象的构建过程涉及多个步骤,并且这些步骤需要按特定顺序执行。
- 举个例子,如果你需要创建一个包含多个组件的电脑对象,其中每个组件都需要按照特定的顺序安装,那么可以使用Java中的建造者模式来实现。具体来说,你可以创建一个电脑类作为产品类,一个电脑建造者类作为抽象建造者,多个具体电脑建造者类实现抽象建造者接口,以及一个电脑指挥者类作为指挥者。在这个模式中,每个具体电脑建造者负责创建某个组件,而电脑指挥者则负责按照特定顺序组装这些组件,最终创建出一个完整的电脑对象。
3.简单的建造者模式示例
public class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
@Override
public String toString() {
return "Product{" +
"partA='" + partA + '\'' +
", partB='" + partB + '\'' +
", partC='" + partC + '\'' +
'}';
}
}
public interface Builder {
void buildPartA();
void buildPartB();
void buildPartC();
Product getProduct();
}
public class ConcreteBuilder implements Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.setPartA("Part A");
}
@Override
public void buildPartB() {
product.setPartB("Part B");
}
@Override
public void buildPartC() {
product.setPartC("Part C");
}
@Override
public Product getProduct() {
return product;
}
}
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
// Usage:
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getProduct();
System.out.println(product);
这段代码中,Product是要构建的产品类,它有三个部分:partA、partB和partC。Builder是抽象建造者接口,定义了构建产品的三个步骤:buildPartA()、buildPartB()和buildPartC(),以及获取产品的方法getProduct()。ConcreteBuilder是具体建造者类,实现了Builder接口
外观模式
1.外观模式是什么
-
外观模式是一种结构型设计模式,它提供了一种简单的方式来访问复杂系统的子系统。外观模式通过定义一个高层接口,隐藏了子系统的复杂性,使客户端代码更加简单和易于使用。
外观模式包含以下几个角色:
- 外观类:提供了一个简单的接口,隐藏了子系统的复杂性。
- 子系统类:实现了子系统的功能,并且可以被外观类调用。
2.简单的外观模式示例
在这个示例中,SubsystemA
、SubsystemB
和 SubsystemC
类表示子系统,实现了子系统的功能,并且可以被外观类调用。Facade
类是外观类,提供了一个简单的接口,隐藏了子系统的复杂性。客户端代码创建了一个外观对象,并调用其 operation()
方法来访问子系统。外观对象在其内部调用子系统的方法,从而实现了访问子系统的功能。
原型模式
1.原型模式是什么
-
原型模式是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需向客户端公开对象创建的细节。这种模式可以用于创建成本高昂或复杂的对象,或者需要大量重复的对象。
2.原型模式的应用场景
-
对象创建成本高昂或复杂:使用原型模式可以通过复制现有对象来创建新对象,而无需重新创建对象,从而减少创建成本和时间。
-
大量重复的对象:使用原型模式可以避免大量重复创建相似对象的问题,提高程序性能。
-
隐藏对象创建细节:使用原型模式可以隐藏对象创建的细节,使客户端代码更简洁、更易于维护。
-
动态配置对象:使用原型模式可以在运行时动态配置对象,从而实现更灵活的程序设计。
3.原型模式原型模式示例代码
在上面的示例代码中,Prototype
类是抽象原型类,定义了用于复制对象的方法clone()
。ConcretePrototype
类是具体原型类,实现了clone()
方法。客户端代码通过创建原型对象,并调用其clone()
方法来复制对象。
策略模式
1.策略模式是什么
-
策略模式是一种行为型设计模式,它允许在运行时动态地选择算法或行为。策略模式将算法或行为封装在独立的类中,使得它们可以互相替换,而不影响客户端代码。这种模式可以提高程序的灵活性和可维护性,并且可以避免使用大量的条件语句。
2.策略模式的应用场景
-
涉及多种算法或行为的程序:使用策略模式可以将不同的算法或行为封装在独立的类中,使得它们可以互相替换,从而实现更灵活的程序设计。
-
需要在运行时动态选择算法或行为的程序:使用策略模式可以在运行时动态地选择算法或行为,而无需修改客户端代码。
-
需要避免使用大量的条件语句的程序:使用策略模式可以避免使用大量的条件语句,从而提高程序的可读性和可维护性。
-
需要将算法或行为的实现细节与客户端代码分离的程序:使用策略模式可以将算法或行为的实现细节封装在独立的类中,从而将其与客户端代码分离,提高程序的模块化程度。
举例: 1. 商场会员 , 白银会员 , 黄金会员 , 钻石会员的的不同折扣
2. 一个支付模块,我要有微信支付、支付宝支付、银联支付等 , 做不同计算
3.策略模式的优点和缺点
策略模式的优点包括:
-
提高程序的灵活性:策略模式将算法或行为封装在独立的类中,使得它们可以互相替换,从而提高程序的灵活性。
-
提高程序的可维护性:策略模式将算法或行为的实现细节封装在独立的类中,从而将其与客户端代码分离,提高程序的可维护性。
-
避免使用大量的条件语句:策略模式可以避免使用大量的条件语句,从而提高程序的可读性和可维护性。
-
提高代码复用性:策略模式将算法或行为封装在独立的类中,使得它们可以在不同的程序中重复使用,提高代码复用性。
策略模式的缺点包括:
-
增加了类的数量:策略模式将每种算法或行为都封装在独立的类中,增加了类的数量,从而增加了程序的复杂度。
-
客户端需要了解不同的策略类:客户端需要了解不同的策略类,并选择合适的策略类,从而增加了客户端代码的复杂度。
-
可能会影响程序性能:由于策略模式需要在运行时动态选择算法或行为,可能会影响程序的性能。
4.策略模式示例代码
在这个示例中,PaymentStrategy
接口定义了支付策略的方法 pay()
。WeChatPayment
、Alipay
和 UnionPay
类实现了 PaymentStrategy
接口,分别表示微信支付、支付宝支付和银联支付策略。PaymentContext
类是支付上下文类,用于调用所选的支付策略的 pay()
方法。客户端代码创建了一个 PaymentContext
对象,并传入所选的支付策略对象,然后调用 pay()
方法来进行支付。由于使用了策略模式,客户端代码可以轻松地切换不同的支付策略,而不需要修改其余的代码。
观察者模式
1.观察者模式是什么
-
观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式包括以下角色:
- 抽象主题(Subject):定义了被观察的对象的接口,可以增加和删除观察者对象。
- 具体主题(ConcreteSubject):实现了抽象主题接口,同时保存了观察者对象的列表,以便在状态发生变化时通知观察者。
- 抽象观察者(Observer):定义了观察者对象的接口,当主题发生变化时会被通知。
- 具体观察者(ConcreteObserver):实现了抽象观察者接口,当接收到主题通知时进行更新。
2.观察者模式应用场景
-
当一个对象的状态发生变化时,需要通知其他对象,并且不知道有多少个对象需要通知时,可以使用观察者模式。
-
当一个对象需要将自己的状态变化通知给其他对象,并且希望这些对象能够自动更新自己的状态时,可以使用观察者模式。
-
当一个对象的状态变化会导致其他对象的行为发生变化时,可以使用观察者模式。
-
当一个对象的状态变化会导致其他对象的状态发生变化时,可以使用观察者模式。
观察者模式在很多框架和库中都有应用,例如 Java 中的事件处理机制、Spring 框架中的事件驱动模型等。此外,观察者模式还可以用于实现 MVC 模式中的视图和控制器之间的通信。
3.观察者模式示例代码
在这个示例中,Subject
接口定义了抽象主题的方法,包括添加、删除和通知观察者。ConcreteSubject
类实现了 Subject
接口,并保存了观察者列表和状态信息。Observer
接口定义了抽象观察者的方法,包括更新方法。ConcreteObserver
类实现了 Observer
接口,并保存了状态信息。客户端代码创建了一个 ConcreteSubject
对象和两个 ConcreteObserver
对象,并将它们添加到主题对象中。然后,客户端代码修改主题对象的状态,从而触发通知所有观察者进行更新。在这个示例中,ConcreteObserver
对象的状态与 ConcreteSubject
对象的状态相同。
适配器模式
1.适配器模式是什么
-
适配器模式是一种结构型设计模式,它可以将一个类的接口转换成客户端所期望的另一种接口,从而使原本不兼容的类能够协同工作。
适配器模式包括以下角色:
- 目标接口(Target):客户端所期望的接口,适配器会实现这个接口。
- 适配器(Adapter):将原本不兼容的类适配成客户端所期望的接口。
- 被适配者(Adaptee):需要被适配的类。
适配器模式有两种实现方式:类适配器和对象适配器。
类适配器使用继承来实现适配器,它继承了被适配者类,并实现了目标接口。对象适配器使用组合来实现适配器,它持有被适配者对象,并实现了目标接口。
2.适配器模式应用场景
-
当需要使用一个已经存在的类,但是它的接口与需要的接口不兼容时,可以使用适配器模式。
-
当需要重用一些现有的类,但是这些类的接口不符合需求时,可以使用适配器模式。
-
当需要创建一个可以复用的类,该类与其他类协作的接口不符合需求时,可以使用适配器模式。
-
当需要透明地使用一些不同的子类时,可以使用适配器模式。
适配器模式在很多框架和库中都有应用,例如 Java 中的 InputStreamReader
类和 OutputStreamWriter
类就是使用了适配器模式,将字节流转换成字符流。此外,适配器模式还可以用于将不同的数据库访问 API 适配成统一的 API,或者将不同格式的数据转换成统一的格式。
3.适配器模式示例代码
在上面的代码中,Target
接口是适配器需要实现的接口,Adaptee
接口是需要被适配的接口。Adapter
类是适配器类,它实现了 Target
接口,并在 request()
方法中调用了 Adaptee
接口的 specificRequest()
方法。ConcreteAdaptee
类是具体的适配者类,它实现了 Adaptee
接口,并提供了具体的实现。在测试类中,我们创建了一个 ConcreteAdaptee
对象,并将其传递给 Adapter
对象,然后调用 Target
接口的 request()
方法,实际上是调用了 Adaptee
接口的 specificRequest()
方法。
装饰器模式
1.装饰器模式是什么
-
装饰器模式是一种结构型设计模式,它允许你在运行时动态地向对象添加功能,而无需修改其源代码。装饰器模式通过创建一个包装对象来实现这一点,这个包装对象包含了原始对象,并在其基础上添加了额外的行为。
装饰器模式的核心思想是将对象的行为分离成不同的层次,并使用组合的方式将这些层次组合在一起。每个层次都可以被单独地扩展和修改,而不会影响到其他层次。这使得装饰器模式具有很好的灵活性和可扩展性。
2.装饰器模式应用场景
-
在不影响其他对象的情况下,动态地添加或删除对象的功能。
-
当不能使用子类继承来扩展对象功能时,可以使用装饰器模式。
-
当需要通过多个对象来组合实现某个功能时,可以使用装饰器模式。
-
当需要在不改变现有代码的情况下,对已有对象的功能进行扩展时,可以使用装饰器模式。
3.装饰器模式示例代码
在上面的代码中,Component
接口是抽象组件,ConcreteComponent
类是具体组件。Decorator
类是抽象装饰器,它包含了一个 Component
对象,并在其基础上添加了额外的行为。ConcreteDecoratorA
和 ConcreteDecoratorB
类是具体装饰器,它们分别添加了不同的行为。
在测试类中,我们创建了一个 ConcreteComponent
对象,并将其传递给 ConcreteDecoratorA
对象,然后将 ConcreteDecoratorA
对象又传递给 ConcreteDecoratorB
对象。最终,我们调用 decoratorB
对象的 operation()
方法,实际上是调用了 ConcreteComponent
对象的 operation()
方法,并在其基础上添加了 ConcreteDecoratorA
和 ConcreteDecoratorB
的额外行为。
博主总结不易 , 多点点关注和赞呀 !!!