说说单例模式,在设计单例模式时,如何防止反射或反序列化攻击
单例模式:当某个类,要求只能存在1个实例时,主要是为了
-
全局访问同个实例,不用到处创建,浪费资源(如数据库连接、文件句柄)
-
配置信息存储:如果应用程序需要存储全局的配置信息
-
状态的共享和同步
-
日志记录:只有一个实例来记录日志,避免多个实例之间的日志重复和混乱。
单例实现方式
-
正常
-
私有化:私有化构造函数
-
静态方法:通过静态方法创建1个实例
-
延迟加载:在第一次使用时创建实例
-
线程安全:在多线程场景中,需保证线程安全
-
-
枚举:枚举是天然的单例和线程安全,不能通过反射机制创建,也不能反序列化
防止反射:在私有构造函数中,增加“实例是否存在”的判断
防止反序列化攻击:重写readResolve方法,返回唯一的实例
-
默认的反序列化,会创建新实例
-
readResolve
方法是ObjectInputStream
在反序列化过程中调用的一个特殊方法,用于在反序列化完成后进行额外的处理
策略模式什么情况下使用
例如,在一个电商系统中,可能需要根据不同的支付方式(如信用卡、支付宝、微信支付等)来处理支付。可以使用策略模式将不同的支付方式封装在不同的策略类中,然后在运行时根据用户选择的支付方式来选择相应的策略类进行支付处理。
-
当需要在运行时动态地选择算法:策略模式允许在运行时根据不同的条件选择不同的算法。这对于需要根据用户输入、系统状态或其他因素来改变算法的情况非常有用。
-
当存在多个相关的算法变体:如果一个类有多个相关的算法变体,使用策略模式可以将这些算法封装在不同的策略类中,使代码更具可读性和可维护性。
-
当算法的实现细节可能会发生变化:如果算法的实现细节可能会发生变化,使用策略模式可以将算法的实现与使用它的代码分离,从而更容易进行修改和扩展。
-
当需要避免大量的条件语句:如果一个类中有大量的条件语句来选择不同的算法,使用策略模式可以将这些条件语句替换为对策略对象的调用,使代码更简洁和易于理解。
-
当需要提高代码的可扩展性:使用策略模式可以使代码更容易扩展,因为可以添加新的策略类来实现新的算法,而不需要修改现有的代码。
设计模式,并提供一些具体的设计模式示例
有 23 种设计模式,它们可以分为三大类:创建型模式、结构型模式和行为型模式
-
创建型模式(Creational Patterns):
-
工厂模式(Factory Pattern):通过工厂类创建对象,隐藏具体实现细节。例如,java.util.Calendar 类的 getInstance() 方法。
-
单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。例如,java.lang.Runtime 类。
-
原型模式(Prototype Pattern):通过复制现有对象来创建新对象。例如,java.lang.Object 类的 clone() 方法。
-
-
结构型模式(Structural Patterns):
-
适配器模式(Adapter Pattern):将一个类的接口转换为另一个类所期望的接口。例如,java.util.Arrays 类的 asList() 方法。
-
装饰器模式(Decorator Pattern):动态地给对象添加额外的功能。例如,java.io.BufferedReader 类。
-
代理模式(Proxy Pattern):为其他对象提供一个代理,以控制对该对象的访问。例如,java.lang.reflect.Proxy 类。
-
-
行为型模式(Behavioral Patterns):
-
观察者模式(Observer Pattern):定义对象间的一对多依赖关系,当一个对象状态改变时,其相关对象会收到通知并自动更新。例如,java.util.Observable 类和 java.util.Observer 接口。
-
策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并使它们可以互换。例如,java.util.Comparator 接口。
-
命令模式(Command Pattern):将请求封装为对象,使得可以用不同的请求对客户进行参数化。例如,java.util.concurrent.Callable 接口。
-
设计模式及应用场景
-
单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。应用场景包括日志记录、数据库连接池等。
-
应用场景:在电商项目中,数据库连接池是一个关键资源。使用单例模式可以确保只有一个数据库连接池实例存在,避免多个实例导致的资源竞争和浪费。
-
具体实现:创建一个私有构造函数,防止外部创建实例。提供一个公共的静态方法来获取唯一的实例,并在需要时初始化连接池。
-
-
工厂模式(Factory Pattern):将对象的创建与使用分离,以便更好地管理对象的创建过程。应用场景包括创建复杂对象、框架中的对象创建等。
-
应用场景:当创建订单时,可能有多种不同类型的订单,如普通订单、促销订单、团购订单等。使用工厂模式可以根据订单类型创建相应的订单对象。
-
具体实现:创建一个抽象工厂类,定义创建订单的接口。针对不同类型的订单,创建具体的工厂类来实现该接口,并在其中创建相应的订单对象。
-
-
建造者模式(Builder Pattern):用于构建复杂对象,将对象的构建过程分解为多个步骤。应用场景包括构建具有多个属性的对象。
-
应用场景:构建复杂的商品对象时,商品可能有多个属性,如名称、价格、描述、图片等。使用建造者模式可以将商品的构建过程分解为多个步骤,使代码更清晰、易读。
-
具体实现:创建一个商品建造者类,定义设置商品属性的方法。在创建商品时,使用建造者类逐步设置属性,最后通过构建方法获取完整的商品对象。
-
-
适配器模式(Adapter Pattern):将不兼容的接口转换为兼容的接口,使原本不兼容的类可以协同工作。应用场景包括系统集成、旧代码复用等。
-
应用场景:与外部支付系统集成时,支付系统的接口可能与项目内部的接口不兼容。使用适配器模式可以将外部支付系统的接口转换为项目内部使用的接口。
-
具体实现:创建一个适配器类,实现项目内部的接口,并在其中调用外部支付系统的接口进行适配。
-
-
装饰模式(Decorator Pattern):动态地为对象添加额外的功能,而不改变其基本结构。应用场景包括对现有功能的扩展、动态添加日志记录等。
-
应用场景:在订单处理过程中,可能需要为订单添加额外的功能,如优惠券应用、积分计算等。使用装饰模式可以动态地为订单添加这些功能。
-
具体实现:创建一个订单抽象类,定义订单的基本操作。针对不同的功能,创建具体的装饰类来扩展订单的功能。在处理订单时,通过装饰类的引用调用相应的功能。
-
-
外观模式(Facade Pattern):为复杂的子系统提供一个简单的接口,隐藏子系统的复杂性。应用场景包括系统的封装、提供简单易用的 API 等。
-
应用场景:提供一个简单的接口给外部系统调用,隐藏内部复杂的业务逻辑。
-
具体实现:创建一个外观类,提供一组简单的方法来处理复杂的业务逻辑。外部系统只需要调用外观类的方法,而不需要了解内部的具体实现。
-
-
观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。应用场景包括事件驱动系统、MVC 架构等。
-
应用场景:当订单状态发生变化时,需要通知相关的模块进行相应的处理。
-
具体实现:创建一个抽象的观察者类,定义接收通知的方法。针对不同的观察者,创建具体的观察者类来实现该抽象类。在订单状态发生变化时,通知所有注册的观察者。
-
-
原型模式(Prototype Pattern):通过复制现有对象来创建新对象,提高对象创建的效率。应用场景包括对象的克隆、避免重复创建相似对象等。
-
应用场景:在用户购物车中,可能需要频繁地复制购物车对象。使用原型模式可以通过复制现有购物车对象来创建新的购物车,提高效率。
-
具体实现:实现 Cloneable 接口,并在 clone() 方法中复制购物车的属性。在需要创建新购物车时,调用 clone() 方法复制现有购物车。
-
-
桥接模式(Bridge Pattern):将抽象部分与实现部分分离,使它们可以独立变化。应用场景包括跨平台应用、不同数据库的连接等。
-
应用场景:处理不同支付方式时,支付方式的抽象与具体实现可能会发生变化。使用桥接模式可以将支付方式的抽象与具体实现分离,使它们可以独立变化。
-
具体实现:创建一个支付方式的抽象类,定义支付的基本操作。针对不同的支付方式,创建具体的支付方式类来实现该抽象类。在支付时,通过抽象类的引用调用具体支付方式的实现。
-
-
组合模式(Composite Pattern):将对象组合成树形结构,以表示部分-整体的层次结构。应用场景包括文件系统、图形界面组件等。
-
应用场景:商品分类通常具有层次结构,使用组合模式可以将商品分类组织成树形结构,方便遍历和管理。
-
具体实现:创建一个抽象的商品分类组件类,包含添加、删除子组件的方法。针对具体的商品分类,创建叶子节点和组合节点类来实现该组件类。
-
-
享元模式(Flyweight Pattern):通过共享对象来减少内存的使用,提高性能。应用场景包括大量相似对象的创建、缓存等。
-
应用场景:处理商品图片时,相同的图片可能会被多次使用。使用享元模式可以共享相同的图片资源,减少内存消耗。
-
具体实现:创建一个图片享元工厂类,维护一个图片对象的池。在需要使用图片时,从池中获取或创建图片对象,并在使用后返回池中。
-
-
代理模式(Proxy Pattern):为其他对象提供一个代理,以控制对该对象的访问。应用场景包括远程代理、虚拟代理等。
-
应用场景:在访问用户信息时,可能需要控制访问权限。使用代理模式可以在访问用户信息之前进行权限检查。
-
具体实现:创建一个用户信息代理类,实现与用户信息相同的接口。在代理类中进行权限检查,并在有权限时调用真实的用户信息类进行操作。
-
-
责任链模式(Chain of Responsibility Pattern):将请求的发送者和接收者解耦,使多个对象都有机会处理请求。应用场景包括审批流程、事件处理等。
-
应用场景:处理订单退款时,可能需要经过多个审批环节。使用责任链模式可以定义不同的审批者,并将它们组织成链,依次处理退款请求。
-
具体实现:创建一个抽象的审批者类,包含处理请求和设置下一个审批者的方法。针对不同的审批者,创建具体的审批者类来实现该抽象类。在处理退款请求时,通过责任链依次传递请求,直到有审批者处理或拒绝。
-
-
命令模式(Command Pattern):将请求封装为对象,以便支持撤销、重做等操作。应用场景包括命令行工具、图形界面的操作等。
-
应用场景:将用户的操作封装为命令,方便进行撤销、重做等操作。
-
具体实现:创建一个命令接口,定义执行和撤销操作的方法。针对不同的操作,创建具体的命令类来实现该接口。在执行操作时,创建相应的命令对象并执行,同时将命令对象存储在历史记录中,以便进行撤销和重做。
-
-
迭代器模式(Iterator Pattern):提供一种顺序访问聚合对象元素的方法,而不需要暴露聚合对象的内部表示。应用场景包括遍历集合、迭代器的实现等。
-
应用场景:遍历商品列表时,需要提供一种统一的遍历方式,而不暴露列表的内部结构。
-
具体实现:创建一个迭代器接口,定义遍历元素的方法。针对商品列表,创建具体的迭代器类来实现该接口。在遍历商品列表时,通过迭代器的引用进行遍历。
-
单例模式(Singleton Pattern):确保一个类只有一个实例存在
public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }
工厂模式(Factory Pattern):定义一个创建对象的接口,但让子类决定实例化哪个类
public interface Shape { void draw(); } public class Circle implements Shape { @Override public void draw() { System.out.println("Drawing a circle"); } } public class Square implements Shape { @Override public void draw() { System.out.println("Drawing a square"); } } public class ShapeFactory { public Shape createShape(String shapeType) { if (shapeType.equalsIgnoreCase("circle")) { return new Circle(); } else if (shapeType.equalsIgnoreCase("square")) { return new Square(); } else { throw new IllegalArgumentException("Invalid shape type"); } } }
观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。 示例:
public interface Observer { void update(String message); } public class ConcreteObserver implements Observer { @Override public void update(String message) { System.out.println("Received message: " + message); } } public class Subject { private List<Observer> observers = new ArrayList<>(); public void attach(Observer observer) { observers.add(observer); } public void detach(Observer observer) { observers.remove(observer); } public void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } }
装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责。
public interface Component { void operation(); } public class ConcreteComponent implements Component { @Override public void operation() { System.out.println("Executing operation in ConcreteComponent"); } } public abstract class Decorator implements Component { protected Component component; public Decorator(Component component) { this.component = component; } @Override public void operation() { component.operation(); } } public class ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component component) { super(component); } @Override public void operation() { super.operation(); System.out.println("Executing additional operation in ConcreteDecoratorA"); } }
策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并使它们可以相互替换。
public interface Strategy { void execute(); } public class ConcreteStrategyA implements Strategy { @Override public void execute() { System.out.println("Executing strategy A"); } } public class ConcreteStrategyB implements Strategy { @Override public void execute() { System.out.println("Executing strategy B"); } } public class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } public void executeStrategy() { strategy.execute(); } }
模板方法模式(Template Method Pattern):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
public abstract class AbstractClass { public void templateMethod() { primitiveOperation1(); abstractOperation(); primitiveOperation2(); } protected void primitiveOperation1() { System.out.println("Executing primitive operation 1"); } protected abstract void abstractOperation(); protected void primitiveOperation2() { System.out.println("Executing primitive operation 2"); } } public class ConcreteClass extends AbstractClass { @Override protected void abstractOperation() { System.out.println("Executing abstract operation in ConcreteClass"); } }
迭代器模式(Iterator Pattern):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
public interface Iterator<E> { boolean hasNext(); E next(); } public interface Aggregate<E> { Iterator<E> iterator(); } public class ConcreteAggregate implements Aggregate<Integer> { private List<Integer> items = new ArrayList<>(); public void addItem(Integer item) { items.add(item); } @Override public Iterator<Integer> iterator() { return new ConcreteIterator(this); } private class ConcreteIterator implements Iterator<Integer> { private int currentIndex = 0; private ConcreteAggregate aggregate; public ConcreteIterator(ConcreteAggregate aggregate) { this.aggregate = aggregate; } @Override public boolean hasNext() { return currentIndex < aggregate.items.size(); } @Override public Integer next() { if (hasNext()) { return aggregate.items.get(currentIndex++); } else { throw new NoSuchElementException(); } } } }