你还在写垃圾代码?快用 Java 8 重构传统设计模式吧,是真的优雅! ...

打印 上一主题 下一主题

主题 870|帖子 870|积分 2610

来源:https://www.cnblogs.com/yjmyzz/p/refactor-design-pattern-using-java8.html
java8中提供的很多新特性可以用来重构传统设计模式中的写法,下面是一些示例:
一、策略模式


上图是策略模式的类图,假设我们现在要保存订单,OrderService接口定义要做什么,而NoSqlSaveOrderStragegy以及MySqlSaveOrderStrategy则提供了二种策略,分别是保存到nosql数据库,以及传统的mysql关系型数据库,最后在OrderServiceExecutor中通过构造函数注入最终要使用的策略。
传统写法,这个场景至少得4个类,代码如下:
OrderService接口:
  1. public interface OrderService {
  2.     void saveOrder(String orderNo);
  3. }
复制代码
Mysql策略实现:
  1. public class MySqlSaveOrderStrategy implements OrderService {
  2.     @Override
  3.     public void saveOrder(String orderNo) {
  4.         System.out.println("order:" + orderNo + " save to mysql");
  5.     }
  6. }
复制代码
Nosql策略实现
  1. public class NoSqlSaveOrderStrategy implements OrderService {
  2.     @Override
  3.     public void saveOrder(String orderNo) {
  4.         System.out.println("order:" + orderNo + " save to nosql");
  5.     }
  6. }
复制代码
Spring Boot 基础就不介绍了,推荐下这个实战教程:
https://github.com/javastacks/spring-boot-best-practice
使用策略的辅助"容器"
  1. public class OrderServiceExecutor {
  2.     private final OrderService service;
  3.     public OrderServiceExecutor(OrderService service) {
  4.         this.service = service;
  5.     }
  6.     public void save(String orderNo) {
  7.         this.service.saveOrder(orderNo);
  8.     }
  9. }
复制代码
运行测试类:
  1. public class OrderServiceTest {
  2.     public static void main(String[] args) {
  3.         OrderServiceExecutor executor1 = new OrderServiceExecutor(new MySqlSaveOrderStrategy());
  4.         executor1.save("001");
  5.         OrderServiceExecutor executor2 = new OrderServiceExecutor(new NoSqlSaveOrderStrategy());
  6.         executor2.save("002");
  7.     }
  8. }
复制代码
重构后,可以省去2个策略实现类,代码如下:
  1. public static void main(String[] args) {
  2.     OrderServiceExecutor executor1 = new OrderServiceExecutor((String orderNo) -> System.out.println("order:" + orderNo + " save to mysql"));
  3.     executor1.save("001");
  4.     OrderServiceExecutor executor2 = new OrderServiceExecutor((String orderNo) -> System.out.println("order:" + orderNo + " save to nosql"));
  5.     executor2.save("002");
  6. }
复制代码
学习资料分享:https://www.javastack.cn/study/
二、模板方法

类图如下,核心思路是把一些通用的标准方法,在抽象父类里仅定义方法签名,实现逻辑交给子类。
比如:会员系统中,每个商家都会有一些营销活动,需要推送某种信息给会员,但是不同的商家推送的内容可能不同,有些需要推送优惠券,有些需要积分通知。

抽象模板类:
  1. public abstract class AbstractPushTemplate {
  2.     public void push(int customerId, String shopName) {
  3.         System.out.println("准备推送...");
  4.         execute(customerId, shopName);
  5.         System.out.println("推送完成\n");
  6.     }
  7.     abstract protected void execute(int customerId, String shopName);
  8. }
复制代码
优惠券的具体模板
  1. public class PushCouponTemplate extends AbstractPushTemplate {
  2.     @Override
  3.     protected void execute(int customerId, String shopName) {
  4.         System.out.println("会员:" + customerId + ",你好," + shopName + "送您一张优惠券");
  5.     }
  6. }
复制代码
积分的具体模板
  1. public class PushScoreTemplate extends AbstractPushTemplate {
  2.     @Override
  3.     protected void execute(int customerId, String shopName) {
  4.         System.out.println("会员:" + customerId + ",你好," + shopName + "送您10个积分");
  5.     }
  6. }
复制代码
使用示例:
  1. AbstractPushTemplate template1 = new PushCouponTemplate();
  2. template1.push(1, "糖果店");
  3. AbstractPushTemplate template2 = new PushScoreTemplate();
  4. template2.push(1, "服装店");
复制代码
显然如果模板的实现方式越多,子类就越多。使用java8重构后,可以把上面的3个模板(包括抽象类模板)减少到1个,参考下面:
  1. public class PushTemplateLambda {
  2.     public void push(int customerId, String shopName, Consumer<Object[]> execute) {
  3.         System.out.println("准备推送...");
  4.         Object[] param = new Object[]{customerId, shopName};
  5.         execute.accept(param);
  6.         System.out.println("推送完成\n");
  7.     }
  8. }
复制代码
借助Consumer这个function interface,可以省去实现子类,具体的实现留到使用时再来决定,如:
  1. new PushTemplateLambda().push(1, "糖果店", (Object[] obj) -> {
  2.     System.out.println("会员:" + obj[0] + ",你好," + obj[1] + "送您一张优惠券");
  3. });
  4. new PushTemplateLambda().push(1, "服装店", (Object[] obj) -> {
  5.     System.out.println("会员:" + obj[0] + ",你好," + obj[1] + "送您10个积分");
  6. });
复制代码
三、观察者模式


思路:基于某个Subject主题,然后一堆观察者Observer注册到主题上,有事件发生时,subject根据注册列表,去通知所有的observer。
Observer接口:
  1. public interface Observer {
  2.     void notify(String orderNo);
  3. }
复制代码
另外,Java 系列面试题和答案全部整理好了,微信搜索Java技术栈,在后台发送:面试,可以在线阅读。
Subject接口:
  1. public interface Subject {
  2.     void registerObserver(Observer o);
  3.     void notifyAllObserver(String orderNo);
  4. }
复制代码
Subject接口实现:
  1. public class SubjectImpl implements Subject {
  2.     private final List<Observer> list = new ArrayList<>();
  3.     @Override
  4.     public void registerObserver(Observer o) {
  5.         list.add(o);
  6.     }
  7.     @Override
  8.     public void notifyAllObserver(String orderNo) {
  9.         list.forEach(c -> c.notify(orderNo));
  10.     }
  11. }
复制代码
观察者的二个实现:
OrderObserver:
  1. public class OrderObserver implements Observer {
  2.     @Override
  3.     public void notify(String orderNo) {
  4.         System.out.println("订单 " + orderNo + " 状态更新为【已支付】");
  5.     }
  6. }
复制代码
StockObserver:
  1. public class StockObserver implements Observer {
  2.     @Override
  3.     public void notify(String orderNo) {
  4.         System.out.println("订单 " + orderNo + " 已通知库房发货!");
  5.     }
  6. }
复制代码
测试一把:
  1. static void test1() {
  2.     Subject subject = new SubjectImpl();
  3.     subject.registerObserver(new OrderObserver());
  4.     subject.registerObserver(new StockObserver());
  5.     subject.notifyAllObserver("001");
  6. }
复制代码
用java8重构后,接口可以提供默认实现方法,我们弄一个新的主题接口
  1. public interface NewSubject {
  2.     List<Observer> list = new ArrayList<>();
  3.     default void registerObserver(Observer o) {
  4.         list.add(o);
  5.     }
  6.     default void nofityAllObserver(String orderNo) {
  7.         list.forEach(c -> c.notify(orderNo));
  8.     }
  9. }
复制代码
使用:
  1. static void test2() {
  2.     NewSubject subject = new NewSubject() {
  3.     };
  4.     subject.registerObserver((String orderNo) -> System.out.println("订单 " + orderNo + " 状态更新为【已支付】"));
  5.     subject.registerObserver((String orderNo) -> System.out.println("订单 " + orderNo + " 已通知库房发货!"));
  6.     subject.nofityAllObserver("002");
  7. }
复制代码
只用2个接口实现了观察者模式。
四、责任链/职责链模式


核心思想:每个处理环节,都有一个“指针”指向下一个处理者,类似链表一样。
Processor接口:
  1. public interface Processor {
  2.     Processor getNextProcessor();
  3.     void process(String param);
  4. }
复制代码
抽象实现类
  1. public abstract class AbstractProcessor implements Processor {
  2.     private Processor next;
  3.     public AbstractProcessor(Processor processor) {
  4.         this.next = processor;
  5.     }
  6.     @Override
  7.     public Processor getNextProcessor() {
  8.         return next;
  9.     }
  10.     @Override
  11.     public abstract void process(String param);
  12. }
复制代码
定义2个具体的实现
  1. public class ProcessorImpl1 extends AbstractProcessor {
  2.     public ProcessorImpl1(Processor processor) {
  3.         super(processor);
  4.     }
  5.     @Override
  6.     public void process(String param) {
  7.         System.out.println("processor 1 is processing:" + param);
  8.         if (getNextProcessor() != null) {
  9.             getNextProcessor().process(param);
  10.         }
  11.     }
  12. }
复制代码
  1. public class ProcessorImpl2 extends AbstractProcessor {
  2.     public ProcessorImpl2(Processor next) {
  3.         super(next);
  4.     }
  5.     @Override
  6.     public void process(String param) {
  7.         System.out.println("processor 2 is processing:" + param);
  8.         if (getNextProcessor() != null) {
  9.             getNextProcessor().process(param);
  10.         }
  11.     }
  12. }
复制代码
使用示例:
  1. static void test1() {
  2.     Processor p1 = new ProcessorImpl1(null);
  3.     Processor p2 = new ProcessorImpl2(p1);
  4.     p2.process("something happened");
  5. }
复制代码
用java8重构后,只需要一个新接口
  1. @FunctionalInterface
  2. public interface NewProcessor {
  3.     Consumer<String> process(String param);
  4. }
复制代码
同样的效果,可以写得很简洁:
  1. static void test2() {
  2.     Consumer<String> p1 = param -> System.out.println("processor 1 is processing:" + param);
  3.     Consumer<String> p2 = param -> System.out.println("processor 2 is processing:" + param);
  4.     p2.andThen(p1).accept("something happened");
  5. }
复制代码
andThen天然就是getNextProcessor的另一种表达。
重要提示:什么时候该用lambda,什么时候不用,这是要看情况的,如果处理逻辑相对比较简单,可以用lamdba来重构,以便让代码更简洁易读,如果处理逻辑很复杂,应该还是用“类”。
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表