利用java8对设计模式的重构
java8中提供的很多新特性可以用来重构传统设计模式中的写法,下面是一些示例:
一、策略模式
上图是策略模式的类图,假设我们现在要保存订单,OrderService接口定义要做什么,而NoSqlSaveOrderStragegy以及MySqlSaveOrderStrategy则提供了二种策略,分别是保存到nosql数据库,以及传统的mysql关系型数据库,最后在OrderServiceExecutor中通过构造函数注入最终要使用的策略。
传统写法,这个场景至少得4个类,代码如下:
OrderService接口:
1 2 3 | public interface OrderService { void saveOrder(String orderNo); } |
Mysql策略实现:
1 2 3 4 5 6 | public class MySqlSaveOrderStrategy implements OrderService { @Override public void saveOrder(String orderNo) { System.out.println( "order:" + orderNo + " save to mysql" ); } } |
Nosql策略实现
1 2 3 4 5 6 | public class NoSqlSaveOrderStrategy implements OrderService { @Override public void saveOrder(String orderNo) { System.out.println( "order:" + orderNo + " save to nosql" ); } } |
使用策略的辅助"容器"
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class OrderServiceExecutor { private final OrderService service; public OrderServiceExecutor(OrderService service) { this .service = service; } public void save(String orderNo) { this .service.saveOrder(orderNo); } } |
运行测试类:
1 2 3 4 5 6 7 8 | public class OrderServiceTest { public static void main(String[] args) { OrderServiceExecutor executor1 = new OrderServiceExecutor( new MySqlSaveOrderStrategy()); executor1.save( "001" ); OrderServiceExecutor executor2 = new OrderServiceExecutor( new NoSqlSaveOrderStrategy()); executor2.save( "002" ); } } |
重构后,可以省去2个策略实现类,代码如下:
1 2 3 4 5 6 7 | public static void main(String[] args) { OrderServiceExecutor executor1 = new OrderServiceExecutor((String orderNo) -> System.out.println( "order:" + orderNo + " save to mysql" )); executor1.save( "001" ); OrderServiceExecutor executor2 = new OrderServiceExecutor((String orderNo) -> System.out.println( "order:" + orderNo + " save to nosql" )); executor2.save( "002" ); } |
二、模板方法
类图如下,核心思路是把一些通用的标准方法,在抽象父类里仅定义方法签名,实现逻辑交给子类。比如:会员系统中,每个商家都会有一些营销活动,需要推送某种信息给会员,但是不同的商家推送的内容可能不同,有些需要推送优惠券,有些需要积分通知。
抽象模板类:
1 2 3 4 5 6 7 8 9 10 | public abstract class AbstractPushTemplate { public void push( int customerId, String shopName) { System.out.println( "准备推送..." ); execute(customerId, shopName); System.out.println( "推送完成\n" ); } abstract protected void execute( int customerId, String shopName); } |
优惠券的具体模板
1 2 3 4 5 6 7 | public class PushCouponTemplate extends AbstractPushTemplate { @Override protected void execute( int customerId, String shopName) { System.out.println( "会员:" + customerId + ",你好," + shopName + "送您一张优惠券" ); } } |
积分的具体模板
1 2 3 4 5 6 7 | public class PushScoreTemplate extends AbstractPushTemplate { @Override protected void execute( int customerId, String shopName) { System.out.println( "会员:" + customerId + ",你好," + shopName + "送您10个积分" ); } } |
使用示例:
1 2 3 4 5 | AbstractPushTemplate template1 = new PushCouponTemplate(); template1.push( 1 , "糖果店" ); AbstractPushTemplate template2 = new PushScoreTemplate(); template2.push( 1 , "服装店" ); |
显然如果模板的实现方式越多,子类就越多。使用java8重构后,可以把上面的3个模板(包括抽象类模板)减少到1个,参考下面:
1 2 3 4 5 6 7 8 9 | public class PushTemplateLambda { public void push( int customerId, String shopName, Consumer<Object[]> execute) { System.out.println( "准备推送..." ); Object[] param = new Object[]{customerId, shopName}; execute.accept(param); System.out.println( "推送完成\n" ); } } |
借助Consumer<T>这个function interface,可以省去实现子类,具体的实现留到使用时再来决定,如:
1 2 3 4 5 6 7 | new PushTemplateLambda().push( 1 , "糖果店" , (Object[] obj) -> { System.out.println( "会员:" + obj[ 0 ] + ",你好," + obj[ 1 ] + "送您一张优惠券" ); }); new PushTemplateLambda().push( 1 , "服装店" , (Object[] obj) -> { System.out.println( "会员:" + obj[ 0 ] + ",你好," + obj[ 1 ] + "送您10个积分" ); }); |
三、观察者模式
思路:基于某个Subject主题,然后一堆观察者Observer注册到主题上,有事件发生时,subject根据注册列表,去通知所有的observer。
Observer接口:
1 2 3 | public interface Observer { void notify(String orderNo); } |
Subject接口:
1 2 3 4 | public interface Subject { void registerObserver(Observer o); void notifyAllObserver(String orderNo); } |
Subject接口实现:
1 2 3 4 5 6 7 8 9 10 11 | public class SubjectImpl implements Subject { private final List<Observer> list = new ArrayList<>(); @Override public void registerObserver(Observer o) { list.add(o); } @Override public void notifyAllObserver(String orderNo) { list.forEach(c -> c.notify(orderNo)); } } |
观察者的二个实现:
OrderObserver:
1 2 3 4 5 6 | public class OrderObserver implements Observer { @Override public void notify(String orderNo) { System.out.println( "订单 " + orderNo + " 状态更新为【已支付】" ); } } |
StockObserver:
1 2 3 4 5 6 | public class StockObserver implements Observer { @Override public void notify(String orderNo) { System.out.println( "订单 " + orderNo + " 已通知库房发货!" ); } } |
测试一把:
1 2 3 4 5 6 | static void test1() { Subject subject = new SubjectImpl(); subject.registerObserver( new OrderObserver()); subject.registerObserver( new StockObserver()); subject.notifyAllObserver( "001" ); } |
用java8重构后,接口可以提供默认实现方法,我们弄一个新的主题接口
1 2 3 4 5 6 7 8 9 10 11 12 | public interface NewSubject { List<Observer> list = new ArrayList<>(); default void registerObserver(Observer o) { list.add(o); } default void nofityAllObserver(String orderNo) { list.forEach(c -> c.notify(orderNo)); } } |
使用:
1 2 3 4 5 6 7 | static void test2() { NewSubject subject = new NewSubject() { }; subject.registerObserver((String orderNo) -> System.out.println( "订单 " + orderNo + " 状态更新为【已支付】" )); subject.registerObserver((String orderNo) -> System.out.println( "订单 " + orderNo + " 已通知库房发货!" )); subject.nofityAllObserver( "002" ); } |
只用2个接口实现了观察者模式。
四、责任链/职责链模式
核心思想:每个处理环节,都有一个“指针”指向下一个处理者,类似链表一样。
Processor接口:
1 2 3 4 5 6 | public interface Processor { Processor getNextProcessor(); void process(String param); } |
抽象实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public abstract class AbstractProcessor implements Processor { private Processor next; public AbstractProcessor(Processor processor) { this .next = processor; } @Override public Processor getNextProcessor() { return next; } @Override public abstract void process(String param); } |
定义2个具体的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class ProcessorImpl1 extends AbstractProcessor { public ProcessorImpl1(Processor processor) { super (processor); } @Override public void process(String param) { System.out.println( "processor 1 is processing:" + param); if (getNextProcessor() != null ) { getNextProcessor().process(param); } } } |
及
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class ProcessorImpl2 extends AbstractProcessor { public ProcessorImpl2(Processor next) { super (next); } @Override public void process(String param) { System.out.println( "processor 2 is processing:" + param); if (getNextProcessor() != null ) { getNextProcessor().process(param); } } } |
使用示例:
1 2 3 4 5 | static void test1() { Processor p1 = new ProcessorImpl1( null ); Processor p2 = new ProcessorImpl2(p1); p2.process( "something happened" ); } |
用java8重构后,只需要一个新接口
1 2 3 4 | @FunctionalInterface public interface NewProcessor { Consumer<String> process(String param); } |
同样的效果,可以写得很简洁:
1 2 3 4 5 | static void test2() { Consumer<String> p1 = param -> System.out.println( "processor 1 is processing:" + param); Consumer<String> p2 = param -> System.out.println( "processor 2 is processing:" + param); p2.andThen(p1).accept( "something happened" ); } |
andThen天然就是getNextProcessor的另一种表达。
重要提示:什么时候该用lambda,什么时候不用,这是要看情况的,如果处理逻辑相对比较简单,可以用lamdba来重构,以便让代码更简洁易读,如果处理逻辑很复杂,应该还是用“类”。
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2016-01-19 jenkins 入门教程(中)
2014-01-19 JAVA CDI 学习(4) - @Alternative/@Default/@Any & Extension
2010-01-19 温故而知新:设计模式之Builder
2010-01-19 温故而知新:设计模式之抽象工厂(AbstractFactory)