1. 代理模式(Proxy Pattern)
1.1 概述
代理模式是一种结构型设计模式,它为另一个对象提供一个替身或占位符,以控制对这个对象的访问。代理对象可以在客户端和目标对象之间插入额外的逻辑,例如访问控制、日志记录、性能监控、远程调用等。
1.2 角色
- Subject(抽象主题):定义了 RealSubject 和 Proxy 的共同接口,这样在任何使用 RealSubject 的地方都可以使用 Proxy。
- RealSubject(真实主题):定义了代理对象所代表的真实对象。
- Proxy(代理):持有对真实主题的引用,并实现与真实主题相同的接口,以便在客户端和真实主题之间进行操作。
1.3 实现
1.3.1 静态代理
代理类在编译时就已经存在,通常由开发者手动创建。
// 抽象主题接口
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;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
// 可以在调用真实主题方法前后添加额外逻辑
System.out.println("Proxy: Pre-processing request.");
realSubject.request();
System.out.println("Proxy: Post-processing request.");
}
}
// 使用示例
public class StaticProxyDemo {
public static void main(String[] args) {
Subject proxy = new Proxy();
proxy.request();
}
}
1.3.2 动态代理
代理类在运行时动态生成,通常使用 Java 的反射机制(java.lang.reflect.Proxy
和 java.lang.reflect.InvocationHandler
)或第三方库(如 CGLIB)。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 抽象主题接口 (同上)
// interface Subject { void request(); }
// 真实主题类 (同上)
// class RealSubject implements Subject { ... }
// 动态代理处理器
class DynamicProxyHandler implements InvocationHandler {
private Object target; // 真实主题对象
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DynamicProxy: Pre-processing request for method: " + method.getName());
// 调用真实主题的方法
Object result = method.invoke(target, args);
System.out.println("DynamicProxy: Post-processing request for method: " + method.getName());
return result;
}
}
// 使用示例
public class DynamicProxyDemo {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
// 创建动态代理实例
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(), // 类加载器
realSubject.getClass().getInterfaces(), // 真实主题实现的接口
new DynamicProxyHandler(realSubject) // 代理处理器
);
proxy.request();
}
}
2. 装饰器模式(Decorator Pattern)
2.1 概述
装饰器模式是一种结构型设计模式,它允许在不改变原有对象结构的情况下,动态地给对象添加新的功能。它比继承更加灵活,可以避免继承体系的臃肿。
2.2 角色
- Component(抽象组件):定义一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent(具体组件):定义一个将要被装饰的原始对象。
- Decorator(抽象装饰器):持有一个 Component 对象的引用,并实现 Component 接口。
- ConcreteDecorator(具体装饰器):实现抽象装饰器,向组件添加新的职责。
2.3 实现
// 抽象组件接口
interface Coffee {
String getDescription();
double getCost();
}
// 具体组件:普通咖啡
class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}
@Override
public double getCost() {
return 5.0;
}
}
// 抽象装饰器
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription();
}
@Override
public double getCost() {
return decoratedCoffee.getCost();
}
}
// 具体装饰器:加牛奶
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public String getDescription() {
return super.getDescription() + ", with Milk";
}
@Override
public double getCost() {
return super.getCost() + 1.5;
}
}
// 具体装饰器:加糖
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public String getDescription() {
return super.getDescription() + ", with Sugar";
}
@Override
public double getCost() {
return super.getCost() + 0.5;
}
}
// 使用示例
public class DecoratorPatternDemo {
public static void main(String[] args) {
// 一杯简单的咖啡
Coffee coffee = new SimpleCoffee();
System.out.println("Description: " + coffee.getDescription() + ", Cost: " + coffee.getCost());
// 加牛奶的咖啡
Coffee milkCoffee = new MilkDecorator(new SimpleCoffee());
System.out.println("Description: " + milkCoffee.getDescription() + ", Cost: " + milkCoffee.getCost());
// 加牛奶和糖的咖啡
Coffee milkAndSugarCoffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
System.out.println("Description: " + milkAndSugarCoffee.getDescription() + ", Cost: " + milkAndSugarCoffee.getCost());
}
}
3. 策略模式(Strategy Pattern)
3.1 概述
策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的客户端而变化。
3.2 角色
- Strategy(抽象策略):定义所有支持的算法的公共接口。
- ConcreteStrategy(具体策略):实现抽象策略接口,提供具体的算法实现。
- Context(上下文):持有一个对抽象策略对象的引用,并提供一个接口,允许客户端设置和切换策略。
3.3 实现
// 抽象策略接口
interface PaymentStrategy {
void pay(double amount);
}
// 具体策略:信用卡支付
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String name;
public CreditCardPayment(String cardNumber, String name) {
this.cardNumber = cardNumber;
this.name = name;
}
@Override
public void pay(double amount) {
System.out.println(amount + " paid with credit card: " + cardNumber + " (Holder: " + name + ")");
}
}
// 具体策略:PayPal 支付
class PaypalPayment implements PaymentStrategy {
private String emailId;
public PaypalPayment(String emailId) {
this.emailId = emailId;
}
@Override
public void pay(double amount) {
System.out.println(amount + " paid using Paypal: " + emailId);
}
}
// 上下文类
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(double amount) {
if (paymentStrategy == null) {
System.out.println("Please select a payment strategy.");
return;
}
paymentStrategy.pay(amount);
}
}
// 使用示例
public class StrategyPatternDemo {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
// 使用信用卡支付
cart.setPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456", "John Doe"));
cart.checkout(100.0);
// 使用 PayPal 支付
cart.setPaymentStrategy(new PaypalPayment("john.doe@example.com"));
cart.checkout(50.0);
}
}
总结
本节继续介绍了三种常用的设计模式:
- 代理模式:为另一个对象提供一个替身,以控制对这个对象的访问,并可以在访问前后添加额外逻辑。
- 装饰器模式:在不改变原有对象结构的情况下,动态地给对象添加新的功能,比继承更灵活。
- 策略模式:定义一系列算法,将每个算法封装起来,并使它们可以相互替换,让算法独立于使用它的客户端而变化。
掌握这些设计模式能够帮助你更好地组织代码,提高代码的复用性、可维护性和扩展性。