Java最常用的几种设计模式详解及适用业务场景
Java设计模式详解及适用业务场景
在软件开发中,设计模式是解决常见问题的最佳实践。通过采用这些设计模式,我们可以提高代码的可维护性、可读性和可扩展性。本文将介绍几种常见的Java设计模式,并结合具体代码示例,探讨它们适用的业务场景。
1. 单例模式(Singleton Pattern)
- 定义:确保一个类只有一个实例,并提供一个全局访问点。
- 优点:节约系统资源,提高系统性能;严格控制访问权限。
- 应用场景:数据库连接池、日志记录器、配置管理器等需要全局唯一实例的场景。
代码示例:
public class Singleton {
// 创建一个静态的实例变量,并初始化为null
private static Singleton instance = null;
// 私有构造函数,防止外部实例化
private Singleton() {}
// 提供一个公共的静态方法,用于返回唯一的实例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
// 其他方法
public void showMessage() {
System.out.println("Hello World!");
}
}
2. 工厂模式(Factory Pattern)
- 定义:通过定义创建对象的接口,让子类决定实例化哪一个类。
- 分类:包括简单工厂模式、工厂方法模式和抽象工厂模式。
- 优点:增加程序的灵活性和可维护性;解耦对象的创建和使用
代码示例:
// 产品接口
interface Shape {
void draw();
}
// 具体产品类
class Circle implements Shape {
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
class Rectangle implements Shape {
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
// 工厂类
class ShapeFactory {
// 使用getShape方法获取对象
public Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
}
return null;
}
}
适用业务场景:
- 对象创建复杂:如涉及大量资源分配、复杂初始化逻辑或需要依赖注入的对象。
- 解耦对象创建与具体实现:客户端代码无需知道对象如何创建,只需知道如何使用。
3. 观察者模式(Observer Pattern)
- 定义:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,所有依赖它的观察者对象都会收到通知并自动更新。
- 优点:实现松耦合,提高系统可维护性;支持广播通信。
- 应用场景:GUI事件处理、发布-订阅系统、消息推送等。
代码示例:
import java.util.ArrayList;
import java.util.List;
// 主题接口
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 具体主题类
class ConcreteSubject implements Subject {
private List<Observer> observers;
private int state;
public ConcreteSubject() {
observers = new ArrayList<>();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(state);
}
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
}
// 观察者接口
interface Observer {
void update(int state);
}
// 具体观察者类
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
public void update(int state) {
System.out.println("Observer " + name + " received state " + state);
}
}
适用业务场景:
- 事件驱动系统:如GUI框架、消息队列系统等,当一个对象的状态改变时需要通知其他对象。
- 实现发布/订阅模型:在内容管理系统、社交媒体平台等,用户可以订阅感兴趣的内容,并在内容更新时收到通知。
4. 策略模式(Strategy Pattern)
- 定义:定义了一系列算法,将每一个算法封装起来,并使它们可以相互替换。
- 优点:提高算法的扩展性和复用性;避免使用多重条件判断。
- 应用场景:需要动态选择算法实现时,如排序算法、资源调度策略等。
代码示例:
// 策略接口
interface Strategy {
int doOperation(int num1, int num2);
}
// 具体策略类
class OperationAdd implements Strategy {
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
class OperationSubtract implements Strategy {
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
class OperationMultiply implements Strategy {
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
// 上下文类
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
适用业务场景:
- 算法选择:在需要根据不同条件选择不同的算法或行为时,如排序算法的选择。
- 多条件分支处理:避免大量if-else语句,提高代码的可维护性和可读性。
5、适配器模式(Adapter Pattern)
- 定义:将一个类的接口转换成客户希望的另外一个接口,使原本由于接口不兼容而不能一起工作的类可以一起工作。
- 优点:提高代码的复用性;符合开闭原则。
- 应用场景:需要使用现有的类,但类的接口不符合系统要求时。
代码示例:
// 目标接口
public interface NewInterface {
void newMethod();
}
// 源接口(老接口)
public class OldClass {
public void oldMethod() {
System.out.println("OldClass: 调用旧方法");
}
}
// 适配器类
public class Adapter implements NewInterface {
private final OldClass oldClass;
public Adapter(OldClass oldClass) {
this.oldClass = oldClass;
}
@Override
public void newMethod() {
oldClass.oldMethod();
}
}
// 测试类
public class AdapterExample {
public static void main(String[] args) {
OldClass oldClass = new OldClass();
NewInterface adapter = new Adapter(oldClass);
adapter.newMethod(); // 调用新接口的方法,但实际调用的是旧接口的方法
}
}
6、装饰器模式(Decorator Pattern)
- 定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活。
- 优点:提高代码的复用性和扩展性;符合开闭原则。
- 应用场景:需要在不修改原有代码的情况下,为对象动态添加功能时。
代码示例:
装饰器模式允许向一个现有的对象添加新的功能,同时不改变其结构。
// 组件接口
interface Component {
void operation();
}
// 具体组件
class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("执行具体组件的操作");
}
}
// 装饰器抽象类
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
// 具体装饰器 A
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("执行具体装饰器 A 的额外操作");
}
}
// 具体装饰器 B
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("执行具体装饰器 B 的额外操作");
}
}
// 测试类
public class DecoratorPatternExample {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratedComponentA = new ConcreteDecoratorA(component);
Component decoratedComponentB = new ConcreteDecoratorB(decoratedComponentA);
decoratedComponentB.operation();
}
}
7、代理模式(Proxy Pattern)
- 定义:为其他对象提供一种代理以控制对这个对象的访问。
- 优点:实现远程代理、虚拟代理、保护代理等功能;隐藏对象的创建细节。
- 应用场景:需要对访问进行控制、延迟加载、日志记录等场景。
代码示例:
代理模式为其他对象提供一种代理以控制对这个对象的访问。
// 接口
interface UserService {
void performAction();
}
// 实际服务类
class RealUserService implements UserService {
@Override
public void performAction() {
System.out.println("执行实际操作");
}
}
// 代理类
class UserServiceProxy implements UserService {
private UserService realUserService;
private String userRole;
public UserServiceProxy(String userRole) {
this.userRole = userRole;
}
@Override
public void performAction() {
if ("admin".equals(userRole)) {
if (realUserService == null) {
realUserService = new RealUserService();
}
realUserService.performAction();
} else {
System.out.println("您没有足够的权限执行此操作");
}
}
public static void main(String[] args) {
// 以管理员身份调用
UserService adminProxy = new UserServiceProxy("admin");
adminProxy.performAction();
// 以普通用户身份调用
UserService normalUserProxy = new UserServiceProxy("normal");
normalUserProxy.performAction();
}
}
8、 外观模式(Facade Pattern)
- 定义:为子系统中的一组接口提供一个统一的接口,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 优点:简化接口,降低客户端与子系统之间的耦合度;提高系统的易用性。
- 应用场景:需要将复杂子系统的接口简化时。
代码示例:
// 子系统A
class SubsystemA {
public void operationA() {
System.out.println("子系统A");
}
}
// 子系统B
class SubsystemB {
public void operationB() {
System.out.println("子系统B");
}
}
// 外观类
class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
public Facade() {
this.subsystemA = new SubsystemA();
this.subsystemB = new SubsystemB();
}
public void operation() {
subsystemA.operationA();
subsystemB.operationB();
}
}
// 测试代码
public class FacadePatternExample {
public static void main(String[] args) {
Facade facade = new Facade();
facade.operation();
}
}
9、 模板方法模式(Template Method Pattern)
- 定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中实现。
- 优点:实现代码复用,提高系统灵活性;符合开闭原则。
- 应用场景:需要在多个子类中实现相同的算法流程,但具体步骤有所差异时。
代码示例:
// 抽象类
abstract class Coffee {
// 模板方法:定义咖啡制作的流程
public final void prepareCoffee() {
boilWater();
brewCoffee();
pourInCup();
addCondiments();
}
// 抽象方法:子类需要实现具体的制作步骤
protected abstract void brewCoffee();
// 钩子方法:子类可以选择覆盖或使用默认实现
protected void addCondiments() {
System.out.println("Adding condiments");
}
// 具体方法:共用的步骤
private void boilWater() {
System.out.println("Boiling water");
}
private void pourInCup() {
System.out.println("Pouring into cup");
}
}
// 具体子类:美式咖啡
class AmericanCoffee extends Coffee {
@Override
protected void brewCoffee() {
System.out.println("Brewing American coffee");
}
}
// 具体子类:拿铁咖啡
class LatteCoffee extends Coffee {
@Override
protected void brewCoffee() {
System.out.println("Brewing Latte coffee");
}
@Override
protected void addCondiments() {
System.out.println("Adding milk and foam");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Coffee coffee = new AmericanCoffee();
coffee.prepareCoffee();
coffee = new LatteCoffee();
coffee.prepareCoffee();
}
}
适用业务场景
- 支付处理系统:支付流程通常包括验证、记账和通知等步骤,但具体的实现可能因支付方式而异。模板方法模式允许定义一个算法的骨架,同时留下一些扩展点供子类实现。
- 图形界面应用程序:在GUI应用程序中,事件处理流程可能相似,但具体的响应可能不同。通过模板方法模式,可以定义一个事件处理的骨架,并在子类中实现具体的响应。
- 产品组装线:在制造工厂中,不同的产品可能需要不同的组装步骤,但总体流程是一致的。模板方法模式可以定义组装的骨架,并在子类中实现具体的组装步骤。