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对设计模式的重构的更多相关文章

  1. 利用js日期控件重构WEB功能

    开发需求:网页中的日期部门(注册页面和查询条件)都用js日期控件重写 页面一:更新员工页面 empUpdate.jsp 中增加 onfocus 事件 入职日期:<input id="h ...

  2. 利用java8新特性,用简洁高效的代码来实现一些数据处理

    定义1个Apple对象: public class Apple {    private Integer id;    private String name;    private BigDecim ...

  3. 图解如何利用Intellij IDEA进行代码重构

    源:https://jingyan.baidu.com/article/c45ad29c64f7e7051653e27d.html 重命名类,打开 Refactor -> Rename 或 Sh ...

  4. python:爬虫入门

    直接上代码吧: 一.爬取某外卖平台的指定商家菜品信息 from urllib import request import json import random url = "https:// ...

  5. 利用vue-router和compoment重构代码--踩坑(一)

    业务主要功能 获取所有的数据库列表 点击某一个数据库列表的时候,右侧分页展示数据 点击右侧某一条数据的时候,现实数据详情 以下是之前的页面,存在以下问题: 前段开发没有工程化(webpack) 主要功 ...

  6. 设计模式 AOP,OOP

    AOP.OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想. 简单说,AOP面向动词领域,OOP面向名词领域 AOP: (Aspect Oriented Programming) 面向切面编 ...

  7. 面向对象设计模式纵横谈:Singelton单件模式(笔记记录)

       李建忠老师讲的<面向对象设计模式纵横谈>,早就看过了,现在有了时间重新整理一下,以前的博客[赛迪网]没有了,现在搬到博客园,重新过一遍,也便于以后浏览. 设计模式从不同的角度分类会得 ...

  8. Java8并发教程:Threads和Executors

    来之:ImportNew 欢迎阅读我的Java8并发教程的第一部分.这份指南将会以简单易懂的代码示例来教给你如何在Java8中进行并发编程.这是一系列教程中的第一部分.在接下来的15分钟,你将会学会如 ...

  9. 大话设计模式C++版——原则和引言

    转贴请注明转自:http://blog.csdn.net/gufeng99/article/details/45832711 读程杰的<大话设计模式>有一段时间了,将其C#版的设计模式代码 ...

随机推荐

  1. python环境下使用tab自动补全命令

    # vim /usr/lib/python2.7/dist-packages/tab.py 加入如下内容: #!/usr/bin/env python # python startup file im ...

  2. 转载:2.1 运行中的Nginx进程间的关系《深入理解Nginx》(陶辉)

    原文:https://book.2cto.com/201304/19624.html 在正式提供服务的产品环境下,部署Nginx时都是使用一个master进程来管理多个worker进程,一般情况下,w ...

  3. Myeclipse10.7安装git插件并将Java项目上传到码云(github)

    注:本文来源:外匹夫的<Myeclipse10.7安装git插件并将Java项目上传到码云(github)> 一.先说说安装egit插件的步骤(安装egit不成功的原因主要是下载的egit ...

  4. 前端工程化-webpack篇之babel-polyfill与babel-runtime(三)

    关于 Babel 如果我们没有配置一些规则,Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API,比如 Iterator.Generator.Set.Maps. ...

  5. oracle表分区的,分区操作,分区查询,子分区查询

    一.摘要 有关表分区的一些维护性操作: 注:分区根据具体情况选择. 表分区有以下优点: 1.数据查询:数据被存储到多个文件上,减少了I/O负载,查询速度提高. 2.数据修剪:保存历史数据非常的理想. ...

  6. IEnumerable和IEnumerator接口

    我们先思考几个问题:1.为什么在foreach中不能修改item的值?(IEnumerator的Current为只读)2.要实现foreach需要满足什么条件?(实现IEnumerator接口来实现的 ...

  7. react-router4 + webpack Code Splitting

    项目升级为react-router4后,就尝试着根据官方文档进行代码分割.https://reacttraining.com/react-router/web/guides/code-splittin ...

  8. Digital biquad filter

    Direct Form 1 The most straightforward implementation is the Direct Form 1, which has the following ...

  9. UVa140 Bandwidth 【最优性剪枝】

    题目链接:https://vjudge.net/contest/210334#problem/F  转载于:https://www.cnblogs.com/luruiyuan/p/5847706.ht ...

  10. P1862输油管道问题

    P1862输油管道问题. . . . .-----------------. . . . . .图像大体是这样,是带权平均数问题,设答案是k,sigama(abs(yi-k*wi))最小,这里的wi是 ...