一、单例模式
1.1 使用场景
在系统中,当某个全局使用的类频繁地进行创建与销毁操作,为节省系统资源并确保实例的唯一性,可使用单例模式。例如,日志记录器在整个系统中通常只需要一个实例来记录日志信息,此时单例模式就非常适用。
1.2 注意事项
- 单例类在整个系统中只能有一个实例。
- 单例类需自行创建并管理这个唯一的实例。
- 单例类要为系统中的其他对象提供获取该实例的方法。
1.3 饿汉模式
饿汉模式是单例模式的一种实现方式,在类加载时就创建单例实例。以下是 Java 代码示例:
public class SingletonHungry {
// 私有静态实例
private static final SingletonHungry instance = new SingletonHungry();
// 私有构造函数,防止外部实例化
private SingletonHungry() {}
// 提供获取实例的方法
public static SingletonHungry getInstance() {
return instance;
}
}
这种方式的优点是简单直接,在类加载时就完成实例的创建,保证了线程安全;缺点是如果实例创建过程复杂或实例在很长时间内不被使用,会造成资源的浪费。
1.4 懒汉模式
懒汉模式是在需要使用实例时才进行创建。为保证线程安全,通常采用双重检查锁定机制。以下是 Java 代码示例:
public class SingletonLazy {
// 私有静态实例
private static SingletonLazy instance;
// 私有构造函数,防止外部实例化
private SingletonLazy() {}
// 提供获取实例的方法
public static SingletonLazy getInstance() {
if (instance == null) {
synchronized (SingletonLazy.class) {
if (instance == null) {
instance = new SingletonLazy();
}
}
}
return instance;
}
}
这种方式的优点是实现了延迟加载,避免了资源的浪费;缺点是实现相对复杂,需要正确处理多线程环境下的并发问题。
二、代理模式
2.1 模式概述
代理模式属于结构型设计模式,一个类(代理类)代表另一个类(目标类)来提供功能。当需要在访问一个类时添加额外的控制逻辑,如权限验证、日志记录等,可使用代理模式。代理类在客户端和目标类之间起到中介作用,客户端通过代理类来访问目标类的方法。
2.2 优点
- 职责清晰:代理类负责处理额外的控制逻辑,目标类专注于核心业务逻辑,使代码结构更加清晰。
- 高扩展性:新增功能或修改控制逻辑时,只需修改代理类,不影响目标类,便于系统的扩展。
- 智能化:可以根据不同的需求,在代理类中灵活地添加各种智能操作。
2.3 缺点
- 性能损耗:由于增加了代理对象,某些类型的代理模式可能会导致请求的处理速度变慢。
- 实现复杂:实现代理模式需要编写额外的代码,部分代理模式的实现逻辑较为复杂。
2.4 使用场景
- 远程代理:用于处理对远程对象的访问,如访问远程服务器上的资源。
- 虚拟代理:实现对象的延迟加载,如在图形系统中,当对象较大或创建成本较高时,使用虚拟代理来延迟对象的创建。
- 保护代理:控制对对象的访问权限,确保只有授权的客户端才能访问目标类。
- Cache 代理:缓存数据,提高数据的访问效率,如缓存数据库查询结果。
2.5 与其他模式的区别
- 与适配器模式的区别:适配器模式主要用于转换对象的接口,使其能够与其他不兼容的接口协同工作;代理模式不改变所代理类的接口,只是在访问接口的过程中增加控制逻辑。
- 与装饰器模式的区别:装饰器模式侧重于为对象添加新的功能,增强对象的能力;代理模式着重于对对象访问的控制。
2.6 静态代理示例
假设我们有一个Subject接口和其实现类RealSubject,现在使用静态代理来添加额外的功能(如日志记录)。
// 定义接口
interface Subject {
void request();
}
// 实现类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: handling request");
}
}
// 代理类
class Proxy implements Subject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("Proxy: Logging before request");
realSubject.request();
System.out.println("Proxy: Logging after request");
}
}
在客户端中使用代理:
public class ProxyPatternDemo {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
proxy.request();
}
}
2.7 动态代理示例
动态代理通过反射机制在运行时动态生成代理类。以下是使用 Java 内置的动态代理机制的示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义接口
interface Subject {
void request();
}
// 实现类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: handling request");
}
}
// 调用处理器
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Dynamic Proxy: Logging before request");
Object result = method.invoke(target, args);
System.out.println("Dynamic Proxy: Logging after request");
return result;
}
}
// 客户端
public class DynamicProxyPatternDemo {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new MyInvocationHandler(realSubject));
proxy.request();
}
}
三、工厂模式
3.1 模式定义
工厂模式是 Java 中常用的创建型设计模式,它提供了一种创建对象的方式,将对象的创建逻辑封装起来,客户端通过工厂类来获取对象,而无需关心对象的具体创建过程。
3.2 使用场景
- 日志记录器:根据不同的需求,选择将日志记录到本地硬盘、系统事件、远程服务器等,可通过工厂模式来创建不同类型的日志记录器。
- 数据库访问:当系统可能使用不同类型的数据库(如 MySQL、Oracle 等)时,使用工厂模式可以方便地切换数据库访问实现。
- 网络协议框架:设计一个连接服务器的框架,涉及多种协议(如 POP3、IMAP、HTTP 等),通过工厂模式创建相应的协议对象。
3.3 注意事项
工厂模式适用于创建复杂对象的场景。对于简单对象,特别是可以直接通过new关键字创建的对象,使用工厂模式可能会增加系统的复杂度,此时不一定需要使用工厂模式。
3.4 简单工厂模式
简单工厂模式是工厂模式的基础形式,它定义了一个工厂类,用于创建产品对象。以下是简单工厂模式的示例:
// 定义产品接口
interface Product {
void operation();
}
// 具体产品类
class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductA: performing operation");
}
}
// 具体产品类
class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductB: performing operation");
}
}
// 工厂类
class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ConcreteProductA();
} else if ("B".equals(type)) {
return new ConcreteProductB();
}
return null;
}
}
在客户端中使用简单工厂:
public class SimpleFactoryPatternDemo {
public static void main(String[] args) {
Product productA = SimpleFactory.createProduct("A");
productA.operation();
Product productB = SimpleFactory.createProduct("B");
productB.operation();
}
}
简单工厂模式的缺点是扩展性差,当需要新增产品时,需要修改工厂类的代码。
3.5 一般工厂模式(工厂方法模式)
工厂方法模式将对象的创建逻辑延迟到具体的工厂子类中实现。以下是工厂方法模式的示例:
// 定义产品接口
interface Product {
void operation();
}
// 具体产品类
class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductA: performing operation");
}
}
// 具体产品类
class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductB: performing operation");
}
}
// 定义工厂接口
interface Factory {
Product createProduct();
}
// 具体工厂类
class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 具体工厂类
class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
在客户端中使用工厂方法模式:
public class FactoryMethodPatternDemo {
public static void main(String[] args) {
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.operation();
Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.operation();
}
}
工厂方法模式提高了代码的扩展性,新增产品时只需创建新的具体工厂类和产品类,无需修改原有的工厂接口和其他具体工厂类。
3.6 抽象工厂模式
抽象工厂模式提供了创建一系列相关或相互依赖对象的接口,由具体的工厂类来实现这些接口。以下是抽象工厂模式的示例:
// 定义产品接口
interface ProductA {
void operationA();
}
interface ProductB {
void operationB();
}
// 具体产品类
class ConcreteProductA1 implements ProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA1: performing operationA");
}
}
class ConcreteProductA2 implements ProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA2: performing operationA");
}
}
class ConcreteProductB1 implements ProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB1: performing operationB");
}
}
class ConcreteProductB2 implements ProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB2: performing operationB");
}
}
// 定义抽象工厂接口
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂类
class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
class ConcreteFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
在客户端中使用抽象工厂模式:
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
productA1.operationA();
productB1.operationB();
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA2.operationA();
productB2.operationB();
}
}
抽象工厂模式适用于创建一系列相关对象的场景,通过抽象工厂接口和具体工厂类的实现,提高了系统的可维护性和扩展性。
四、观察者模式
4.1 模式概念
观察者模式是一种行为型设计模式,当对象间存在一对多关系时使用。一个对象(被观察者)的状态发生改变时,会自动通知所有依赖它的对象(观察者)。
4.2 应用场景
例如,在股票交易系统中,多个投资者(观察者)关注某只股票(被观察者)的价格变化。当股票价格发生变化时,系统会自动通知所有关注该股票的投资者。
4.3 示例代码
import java.util.ArrayList;
import java.util.List;
// 定义被观察者接口
interface Observable {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体被观察者类
class Stock implements Observable {
private String symbol;
private double price;
private List<Observer> observers = new ArrayList<>();
public Stock(String symbol) {
this.symbol = symbol;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
notifyObservers();
}
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(this);
}
}
}
// 定义观察者接口
interface Observer {
void update(Observable observable);
}
// 具体观察者类
class Investor implements Observer {
private String name;
public Investor(String name) {
this.name = name;
}
@Override
public void update(Observable observable) {
if (observable instanceof Stock) {
Stock stock = (Stock) observable;
System.out.println(name + " received update: " + stock.getPrice());
}
}
}
在客户端中使用观察者模式:
public class ObserverPatternDemo {
public static void main(String[] args) {
Stock stock = new Stock("AAPL");
Investor investor1 = new Investor("Investor 1");
Investor investor2 = new Investor("Investor 2");
stock.addObserver(investor1);
stock.addObserver(investor2);
stock.setPrice(150.0);
}
}
五、享元模式
5.1 模式原理
享元模式是一种结构型设计模式,它通过共享对象来减少对象的创建数量,从而降低内存占用和提高性能。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
5.2 优点
- 大大减少对象的创建,降低系统的内存消耗,提高系统的性能。
- 提高了对象的复用性,减少了资源的浪费。
5.3 缺点
- 提高了系统的复杂度,需要准确区分对象的外部状态和内部状态。
- 外部状态的管理需要额外的工作,且外部状态应保持稳定,否则可能会导致系统混乱。
5.4 使用场景
- 系统中有大量相似对象,如游戏中的大量相同类型的角色、地图元素等。
- 需要缓冲池的场景,如数据库连接池、线程池等。
5.5 示例代码
import java.util.HashMap;
import java.util.Map;
// 定义享元接口
interface Shape {
void draw();
}
// 具体享元类
class Circle implements Shape {
private String color;
private int x;
private int y;
private int radius;
public Circle(String color) {
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setRadius(int radius) {
this.radius = radius;
}
上述六种设计模式从不同角度为软件开发提供了解决方案。单例模式确保实例唯一性,有效节省资源;代理模式通过中间层实现对目标对象的访问控制与功能增强;工厂模式将对象创建逻辑封装,便于管理与扩展;观察者模式实现对象间的联动响应;享元模式通过对象共享减少内存占用;策略模式支持算法的动态切换,提升系统灵活性。这些设计模式各有优劣和适用场景,开发者在实际项目中,需根据具体需求与业务场景灵活选择、组合运用,从而构建出结构清晰、可维护性高、性能优良的软件系统 。