利用java8对设计模式的重构
java8中提供的很多新特性可以用来重构传统设计模式中的写法,下面是一些示例:
一、策略模式
上图是策略模式的类图,假设我们现在要保存订单,OrderService接口定义要做什么,而NoSqlSaveOrderStragegy以及MySqlSaveOrderStrategy则提供了二种策略,分别是保存到nosql数据库,以及传统的mysql关系型数据库,最后在OrderServiceExecutor中通过构造函数注入最终要使用的策略。
传统写法,这个场景至少得4个类,代码如下:
OrderService接口:
- public interface OrderService {
- void saveOrder(String orderNo);
- }
Mysql策略实现:
- public class MySqlSaveOrderStrategy implements OrderService {
- @Override
- public void saveOrder(String orderNo) {
- System.out.println("order:" + orderNo + " save to mysql");
- }
- }
Nosql策略实现
- public class NoSqlSaveOrderStrategy implements OrderService {
- @Override
- public void saveOrder(String orderNo) {
- System.out.println("order:" + orderNo + " save to nosql");
- }
- }
使用策略的辅助"容器"
- public class OrderServiceExecutor {
- private final OrderService service;
- public OrderServiceExecutor(OrderService service) {
- this.service = service;
- }
- public void save(String orderNo) {
- this.service.saveOrder(orderNo);
- }
- }
运行测试类:
- 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个策略实现类,代码如下:
- 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");
- }
二、模板方法
类图如下,核心思路是把一些通用的标准方法,在抽象父类里仅定义方法签名,实现逻辑交给子类。比如:会员系统中,每个商家都会有一些营销活动,需要推送某种信息给会员,但是不同的商家推送的内容可能不同,有些需要推送优惠券,有些需要积分通知。
抽象模板类:
- 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);
- }
优惠券的具体模板
- public class PushCouponTemplate extends AbstractPushTemplate {
- @Override
- protected void execute(int customerId, String shopName) {
- System.out.println("会员:" + customerId + ",你好," + shopName + "送您一张优惠券");
- }
- }
积分的具体模板
- public class PushScoreTemplate extends AbstractPushTemplate {
- @Override
- protected void execute(int customerId, String shopName) {
- System.out.println("会员:" + customerId + ",你好," + shopName + "送您10个积分");
- }
- }
使用示例:
- AbstractPushTemplate template1 = new PushCouponTemplate();
- template1.push(1, "糖果店");
- AbstractPushTemplate template2 = new PushScoreTemplate();
- template2.push(1, "服装店");
显然如果模板的实现方式越多,子类就越多。使用java8重构后,可以把上面的3个模板(包括抽象类模板)减少到1个,参考下面:
- 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,可以省去实现子类,具体的实现留到使用时再来决定,如:
- 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接口:
- public interface Observer {
- void notify(String orderNo);
- }
Subject接口:
- public interface Subject {
- void registerObserver(Observer o);
- void notifyAllObserver(String orderNo);
- }
Subject接口实现:
- 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:
- public class OrderObserver implements Observer {
- @Override
- public void notify(String orderNo) {
- System.out.println("订单 " + orderNo + " 状态更新为【已支付】");
- }
- }
StockObserver:
- public class StockObserver implements Observer {
- @Override
- public void notify(String orderNo) {
- System.out.println("订单 " + orderNo + " 已通知库房发货!");
- }
- }
测试一把:
- static void test1() {
- Subject subject = new SubjectImpl();
- subject.registerObserver(new OrderObserver());
- subject.registerObserver(new StockObserver());
- subject.notifyAllObserver("001");
- }
用java8重构后,接口可以提供默认实现方法,我们弄一个新的主题接口
- 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));
- }
- }
使用:
- 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接口:
- public interface Processor {
- Processor getNextProcessor();
- void process(String param);
- }
抽象实现类
- 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个具体的实现
- 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);
- }
- }
- }
及
- 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);
- }
- }
- }
使用示例:
- static void test1() {
- Processor p1 = new ProcessorImpl1(null);
- Processor p2 = new ProcessorImpl2(p1);
- p2.process("something happened");
- }
用java8重构后,只需要一个新接口
- @FunctionalInterface
- public interface NewProcessor {
- Consumer<String> process(String param);
- }
同样的效果,可以写得很简洁:
- 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来重构,以便让代码更简洁易读,如果处理逻辑很复杂,应该还是用“类”。
利用java8对设计模式的重构的更多相关文章
- 利用js日期控件重构WEB功能
开发需求:网页中的日期部门(注册页面和查询条件)都用js日期控件重写 页面一:更新员工页面 empUpdate.jsp 中增加 onfocus 事件 入职日期:<input id="h ...
- 利用java8新特性,用简洁高效的代码来实现一些数据处理
定义1个Apple对象: public class Apple { private Integer id; private String name; private BigDecim ...
- 图解如何利用Intellij IDEA进行代码重构
源:https://jingyan.baidu.com/article/c45ad29c64f7e7051653e27d.html 重命名类,打开 Refactor -> Rename 或 Sh ...
- python:爬虫入门
直接上代码吧: 一.爬取某外卖平台的指定商家菜品信息 from urllib import request import json import random url = "https:// ...
- 利用vue-router和compoment重构代码--踩坑(一)
业务主要功能 获取所有的数据库列表 点击某一个数据库列表的时候,右侧分页展示数据 点击右侧某一条数据的时候,现实数据详情 以下是之前的页面,存在以下问题: 前段开发没有工程化(webpack) 主要功 ...
- 设计模式 AOP,OOP
AOP.OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想. 简单说,AOP面向动词领域,OOP面向名词领域 AOP: (Aspect Oriented Programming) 面向切面编 ...
- 面向对象设计模式纵横谈:Singelton单件模式(笔记记录)
李建忠老师讲的<面向对象设计模式纵横谈>,早就看过了,现在有了时间重新整理一下,以前的博客[赛迪网]没有了,现在搬到博客园,重新过一遍,也便于以后浏览. 设计模式从不同的角度分类会得 ...
- Java8并发教程:Threads和Executors
来之:ImportNew 欢迎阅读我的Java8并发教程的第一部分.这份指南将会以简单易懂的代码示例来教给你如何在Java8中进行并发编程.这是一系列教程中的第一部分.在接下来的15分钟,你将会学会如 ...
- 大话设计模式C++版——原则和引言
转贴请注明转自:http://blog.csdn.net/gufeng99/article/details/45832711 读程杰的<大话设计模式>有一段时间了,将其C#版的设计模式代码 ...
随机推荐
- centos7的安装主要步骤选择
选择语言,选择英语 选择时区done确认选择 安全策略,选择默认 安装源文件 软件包选择,此处选择 最小安装 选择磁盘,并分区
- 如何在CentOS 7上安装Munin
在CentOS 7上安装Munin 首先我们需要在我们的系统中添加EPEL仓库. yum install epel-release 步骤2.安装LAMP(Linux,Apache,MariaDB,PH ...
- js学习、备忘
字符串使用单引号’abc’.(双引号也行.推荐:html→双引号,js→单引号)===严格等于.!==严格不等于if(x) 当x为undefined.null和0的时候都为false:需注意当x为0 ...
- windows下升级node&npm
一.升级npm npm install -g npm 二.升级node 1.查询node的安装目录 where node 2.在官网下载最新的安装包,直接覆盖安装即可. https://nodejs. ...
- Redhat5_linux 系统环境下 oracl11g的安装教程图解
linux_oracl11g 安装步骤 操作系统的安装敬请参考此文:VM 安装 linux Enterprise_R5_U4_Server_I386_DVD教程图解 设置linux服务器的静态地址请参 ...
- wampserver修改端口号后,phpMyAdmin进不去,需要修改相关配置文件
一.修改Apache端口 1.在界面中选Apache,弹出隐藏菜单选项,打开配置文件httpd.conf: 2.找到 Listen 80: 3.将 80 改成 8080(当然自己也可以设定别的不使用的 ...
- BZOJ1297 [SCOI2009]迷路 矩阵乘法
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1297 题意概括 有向图有 N 个节点,从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. ...
- 004 Spark中的local模式的配置以及测试
一:介绍 1.Spark的模式 Local:本地运行模式,主要用于开发.测试 Standalone:使用Spark自带的资源管理框架运行Spark程序,30%左右 Yarn: 将spark应用程序运行 ...
- Unity Standard Assets Example Project
参考链接:http://blog.csdn.net/jaikydota163/article/details/52751976
- 《Gradle权威指南》--Gradle任务
No1: 多种方式创建任务 def Task ex41CreateTask1 = task(ex41CreateTask1) ex41CreateTask1.doLast{ println " ...