设计模式之策略模式、代理模式
策略模式
策略模式面试回答:
策略模式在我们平时开发过程中的主要作用是在具有一个逻辑的处理具有多个处理方法时使用,这些方法做的事是一样的。
首先策略模式需要一个策略接口,后面不同得方案通过实现接口实现,比如各种排序算法可以使用策略模式,写一个排序策略接口,后面实现冒泡、快排的实现类,后续使用时直接将需要排序的数据传递给实现类就可以,如果后续有别的排序逻辑也可以加入,这样符合开闭原则。
策略模式使用场景
- 支付系统
- 排序算法
- 折扣促销
- 数据校验
1. 支付系统(多种支付方式)
场景:系统需要支持多种支付方式(支付宝、微信、银行卡、PayPal 等),且未来可能新增支付方式。
实现:
- 定义支付策略接口
PaymentStrategy
,包含pay(amount)
方法。 - 每个支付方式实现该接口(如
AlipayStrategy
、WeChatPayStrategy
)。 - 用户选择支付方式时,动态注入对应的策略。
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略:支付宝
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount);
}
}
// 上下文类(封装策略)
public class PaymentContext {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(double amount) {
strategy.pay(amount);
}
}
// 使用示例
PaymentContext context = new PaymentContext();
context.setStrategy(new AlipayStrategy());
context.executePayment(100.0);
2. 排序算法(灵活切换算法)
场景:需要根据数据规模动态选择排序算法(如快速排序、归并排序、冒泡排序)。
实现:
- 定义排序策略接口
SortStrategy
,包含sort(int[] array)
方法。 - 不同排序算法实现该接口。
- 根据数据特征(如规模、有序性)自动选择合适的策略。
public interface SortStrategy {
void sort(int[] array);
}
public class QuickSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
// 实现快速排序
}
}
// 使用示例
public class Sorter {
private SortStrategy strategy;
public Sorter(SortStrategy strategy) {
this.strategy = strategy;
}
public void performSort(int[] array) {
strategy.sort(array);
}
}
3. 折扣与促销(动态计算价格)
场景:电商平台需要支持多种促销策略(满减、折扣券、会员价、秒杀价等)。
实现:
- 定义折扣策略接口
DiscountStrategy
,包含applyDiscount(double price)
方法。 - 不同促销规则实现该接口。
- 根据活动类型动态切换折扣策略。
public interface DiscountStrategy {
double applyDiscount(double originalPrice);
}
public class CouponDiscountStrategy implements DiscountStrategy {
@Override
public double applyDiscount(double price) {
return price * 0.8; // 8折优惠
}
}
// 使用示例
public class PricingService {
private DiscountStrategy discountStrategy;
public void setDiscountStrategy(DiscountStrategy strategy) {
this.discountStrategy = strategy;
}
public double calculatePrice(double originalPrice) {
return discountStrategy.applyDiscount(originalPrice);
}
}
4. 日志记录(输出到不同目标)
场景:日志需要支持多种输出方式(控制台、文件、数据库、远程服务器)。
实现:
- 定义日志策略接口
LoggingStrategy
,包含log(String message)
方法。 - 不同输出方式实现该接口。
- 根据环境配置(如开发/生产)切换日志策略。
public interface LoggingStrategy {
void log(String message);
}
public class FileLoggingStrategy implements LoggingStrategy {
@Override
public void log(String message) {
// 写入文件
}
}
// 使用示例
public class Logger {
private LoggingStrategy strategy;
public Logger(LoggingStrategy strategy) {
this.strategy = strategy;
}
public void doLog(String message) {
strategy.log(message);
}
}
5. 数据验证(多种校验规则)
场景:表单字段需要支持不同校验规则(邮箱、手机号、密码强度等)。
实现:
- 定义校验策略接口
ValidationStrategy
,包含validate(String input)
方法。 - 不同校验规则实现该接口。
- 根据字段类型动态选择校验策略。
public interface ValidationStrategy {
boolean validate(String input);
}
public class EmailValidationStrategy implements ValidationStrategy {
@Override
public boolean validate(String input) {
return input.matches("^[a-zA-Z0-9_+&*-]+@[a-zA-Z0-9-]+\\.[a-zA-Z]{2,7}$");
}
}
// 使用示例
public class Validator {
private ValidationStrategy strategy;
public Validator(ValidationStrategy strategy) {
this.strategy = strategy;
}
public boolean isValid(String input) {
return strategy.validate(input);
}
}
策略模式的核心优势
- 开闭原则:新增策略无需修改已有代码。
- 消除条件语句:避免复杂的
if-else
或switch
分支。 - 动态切换行为:运行时灵活替换算法。
- 代码复用:策略可以被多个上下文共享。
通过以上场景可以看出,策略模式非常适合 算法或行为需要灵活扩展和替换 的场景,是解耦和封装变化的利器。
代理模式
面试回答:
代理模式是将一个在不修改本身业务逻辑下,创造一个代理对象去实现统一的方法,比如需要计算一个对用户逻辑的处理耗时、打印日志,,可以创建一个用户代理对象去计算耗时而不用在其实现的方法内编写计算耗时的方法,这样可以降低耦合度,符合开闭原则
JAVA实现
package proxy;
public class BigStar implements Star{
private String name;
public BigStar(String name){
this.name=name;
}
public String sing(){
System.out.println(name+"---唱歌");
return "谢谢!!!";
}
public void dance(){
System.out.println(name+"---跳舞");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package proxy;
public interface Star {
String sing();
void dance();
}
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static Star createStarProxy(BigStar bigStar){
return (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), new Class[]{Star.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("sing")){
System.out.println("收钱1000万");
} else if (method.getName().equals("dance")) {
System.out.println("收钱200万");
}
return method.invoke(bigStar,args);
}
});
}
}
package proxy;
public class Test {
public static void main(String[] args) {
BigStar bigStar= new BigStar("周杰伦");
Star starProxy = ProxyUtil.createStarProxy(bigStar);
starProxy.dance();
starProxy.sing();
}
}
jdk与cglib代理
特性 | JDK动态代理 | CGLIB代理 |
---|---|---|
实现原理 | 基于接口实现代理,运行时生成接口的代理类。 | 基于继承实现代理,运行时生成目标类的子类。 |
代理方式 | 通过java.lang.reflect.Proxy 类创建代理对象。 |
通过Enhancer 类生成子类代理对象。 |
方法调用 | 通过反射调用目标方法(method.invoke() )。 |
通过FastClass 机制直接调用方法,避免反射开销。 |
本文作者:rmxob
本文链接:https://www.cnblogs.com/rmxob/p/18714500
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗