极客大学架构师训练营 框架开发 设计原则 设计模式 反应式编程框架 上课总结 第五课
说明
框架开发
讲师:李智慧
框架设计原则 (SOLID)
开闭原则(OCP - Open–closed principle)
对扩展是开发,对现有修改是关闭。
使用多态,使用抽象。策略模式,适配器模式,观察者模式。
依赖倒置原则(DIP - Dependency inversion principle)
高层不依赖低层,低层也不依赖高层。高层定义抽象接口,低层实现高层定义的接口。
比如Tomcat,Spring,JUnit,我们不需要调用框架的代码。我们基于框架提供的接口来编程。 架构师要有开发框架的能力和思维,这才能区别于普通的工程师。
正常的调用顺序
依赖倒置以后
Liskov 替换原则(LSP - Liskov substitution principle)
所有的父类,都可以替换为子类。 子类比父类更严格,子类方法约束开放性要比父类大。比如父类是protected修饰,子类只能是protected或者public。
单一职责原则(SRP - Single-responsibility principle)
一个类只有一个引起其变化的原因。
如果一个类会有多个原因引起变化,则要分为多个类。
接口隔离原则(ISP - Interface segregation principle)
反应式编程框架 Flower 设计
程序是如何运行又是如何崩溃的
方法调用都是同步的,很快就会把线程池里面的线程给消费完了,导致排队阻塞。
Flower 可以显著提升系统性能
异步处理,通过消息来通信。
Flower 反应式重构前后性能对比
Flower 可以显著提升系统性能 架构图
Flower 实现异步的基础是 Akka 的 Actor
Sender 到 Actor 的通信是异步的,通过消息 Message 进行通信。
5分钟上手 Flower 反应式编程
Akka编程实例(Java)
public class Hello extends UntypedActor {@Overridepublic void onReceive(Object message) {System.out.println("Hello, world!");}
}
调用
ActorRef hello = ...
hello.tell("Hi!");
1 开发异步服务Service
public class ServiceA implements Service<String, String> {public String process(String message, ServiceContext context) {return ((String) message).trim();}return "";
}
2. 编排Service流程 serviceA -> serviceB -> serviceC
ServiceFlow.getOrCreate(flowName, servcieFactory).buildFlow(ServiceA.class, ServiceB.class).buildFlow(ServiceB.class, ServiceC.class);
3. 调用异步服务
flowerFactory.getServiceFacade().asyncCallService(flowName, "Hello World!");
Flower 可视化流程编排
// -> Service1 -> Service2 -> Service5 -> Service4
// ^ | ^ |
// | -> Service3 -| |
// |______________________________________________|Service1 -> Service2
Service1 -> Service3
Service2 -> Service5
Service3 -> Service5
Service5 -> Service4
Service4 -> Service1
兼容 Spring 的 Flower Web 开发
@RestController
@RequestMapping("/order/")
@Flower(value = "createOrderFlow", flowNumber = 32)
public class CreateOrderController extends FlowerController {@RequestMapping(value = "createOrder")public void createOrder(OrderExt orderDTO, HttpServletRequest req) throws IOException {doProcess(orderDTO, req);}
}
protected void doProcess(Object param, HttpServletRequest req) throws IOExeption {AsyncContext context = null;if (req != null) {context = req.startAsync();}flowRouter.asyncCallService(param, context);
}
Flower 异步数据库访问
@FlowerService
public class UserService implements Service<User, CompletableFuture<Serializable>> {@Autowiredprivate UserDao userDao;@overridepublic CompletableFuture<Serializable> process(User message, ServiceContext context) throws Throwable {System.out.println("handle user message: " + message);return userDao.insert(message);}}
Flower 核心模块
publci class ServiceActor extends UntypedActor {Service service;Set<ActorRef> nextServiceActors;public ServiceActor(String serviceName) throws Exception {this.service = ServiceFactory.getService(serviceName);nextServiceActors = new HashSet<ActorRef>();Set<String> nextServiceNames = ServiceFlow.getNextFlow(serviceName);if (nextServiceNames != null && !nextServiceNames.isEmpty()) {for (String str : nextServiceNames) {nextServiceActors.add(ServiceActorFactory.buildServiceActor(str));}}}@Overridepublic void onReceive(Object arg0) throws Throwable {Object nextServiceActors = service.process(arg0);if (nextServiceActors != null && !nextServiceActors.isEmpty()) {for (ActorRef actor : nextServiceActors) {actor.tell(o, getSelf());}}}
}
package com.ly.train.flower.common.actor;public class ServiceFacade {public static void callService(String serviceName, Object o) throws Exception {ServiceActorFactory.buildServiceActor(serviceName).tell(o, null);}
}public class ServiceActorFactory {final static ActorSystem system = ActorSystem.create("LocalFlower");private static FiniteDuration duration = Duration.create(3, SECONDS);public static Map<String, ActorRef> map = new HashMap<String, ActorRef>();public static ActorRef buildServiceActor(String serviceName) throws Exception {ActorRef actor = map.get(serviceName);if (actor != null) {return actor;}actor = system.actorOf(Props,create(ServiceActor.class, serviceName));return actor;}
}
Flower 的分布式异步微服务解决方案
为什么选择 Flower
Flower 与 WebFlux、RxJava 的比较优势
- 开发工程师无需学习函数式编程即可开发反应式系统
- 纯消息驱动,可以实现更灵活的扩展(事件溯源、分布式事务、限流)。
更好的性能与更低的成本
- 更好的性能意味着用更少的机器就可以满足系统的并发压力。
更高的可用性
- 消息驱动天然限流特性使系统在过高并发和部分组件失效的情况下保障系统不会崩溃。
开源地址:
https://github.com/zhihuili/flower
面向对象的设计模式
设计模式的作用
设计模式的定义
什么是设计模式?
- 每一种模式都描述了一种问题的通用解决方案。这种问题在我们的环境中,不停地出现。
- 设计模式是一种可重复使用的解决方案。
一个设计模式的四个部分:
- 模式的名称 - 由少量的字组成的名称,有助于我们表达我们的设计。
- 待解问题 - 描述了何时需要运用这种模式,以及运用模式的环境(上下文)。
- 解决方案 - 描述了组成设计的元素(类和对象)、它们的关系、职责以及合作。但这种解决方案是抽象的,它不代表具体的实现。
- 结论 - 运用这种方案所带来的利和弊。主要是指它对系统的弹性、扩展性和可移植性的影响。
设计模式的分类
从功能分
- 创建模式(Creational Patterns)
☞ 对类的实例化过程的抽象。 - 结构模式(Structural Patterns)
☞ 将类或对象结合在一起形成更大的结构。 - 行为模式(Behavioral Patterns)
☞ 对在不同的对象之间划分责任和算法的抽象化。
从方式分
- 类模式
☞ 以继承的方式实现模式,静态的。 - 对象模式
☞ 以组合的方式实现模式,动态的。
排序问题 – 如何创建一个对象?
利用 简单工厂
简单工厂及 Client 程序
public class SorterFactory {public static <T> Sorter<T> getSorter() {return new BubbleSorter<T>();}
}public class Client {public static void main() {Integer[] array = { 5, 4, 9, 7, 6, 3, 8, 1, 0, 2};Sorter<Integer> sorter = SorterFactory.getSorter();Sortable<Integer> sortable = SortableFactory.getSortable(array);Comparator<Integer> comparator = ComparatorFactory.getComparator();sorter.sort(sortable, comparator);......}
}
简单工厂的优缺点
优点:
- 使 Client 不再依赖 Sorter 的具体实现(如 BubbleSorter)
- 对 Client 实现 OCP - 增加 Sorter 不影响 Client
缺点:
- 对 Factory 未实现 OCP - 增加 Sorter 需要修改 Factory
对简单工厂的改进一
class SorterFactory_2 {@SuppressWarnings("unchecked")public static <T> Sorter<T> getSorter (String implClass) {try {Class impl = Class.forName(implClass);return (Sorter<T>) impl.newInstance();} catch (Exception e) {throw new IllegalArgumentException("Illegal class name:" + implClass, e);}}
}Sorter<Integer> sorter = SorterFactory_2.getSorter("demo.sort.impl.BubbleSorter");
改进一所存在的问题
解决了 Factory 的 OCP 问题吗?
- 增加 Sorter 实现时,不需要修改 Factory 了
- 但是仍然需要修改 Client
其它问题
- 丧失了编译时的类型安全。
☞ Client 和 Factory 均类型不安全。 - Client 仍然 ”知道“ Sorter 的实现是什么。
- 限制了 Sorter 的实现只能通过 ”默认构造函数“ 创建
对简单工厂的改进二
class SorterFactory_3 {private final static Properties IMPLS = loadImpls();private static Properties loadImpls() {Properties defaultImpls = new Properties();Properties impls = new Properties(defaultImpls);defaultImpls.setProperty("sorter", "demo.sort.impl.BubbleSorter");try {impls.load(SorterFactory_3.class.getResourceAsStream("sort.properties"));} catch ( IOException e) {throw new RuntimeException(e);}return impls;}@SuppressWarning("unchecked")public static <T> Sorter<T> getSorter() {String implClassName = IMPLS.getProperty("sorter");try {Class implClass = Class.forName(implClassName);return (Sorter<T>) implClass.newInstance();} catch (Exception e) {throw new IllegalArgumentException("Illegal class name: " + implClassName, e);}}
}
创建 sort.proproties
文件
sorter=demo.sort.impl.BubbleSorter
改进二的优缺点
优点
- 满足 OCP?
☞ 对 Client 和 Factory 均满足
☞ 满足 OCP 方法
☞ 抽象
☞ 动态编程(即将编译时类型检查转变成运行时检查)
缺点
- 缺少编译时类型安全
- 限制了 Sorter 的实现只能通过 ”默认构造函数“ 创建
☞ 假如需要传递参数?
简单工厂改进做法其实相当重要
- 简单工厂非常重要,是许多其它模式的基础
- 而该机制解决了简单工厂模式最致命的问题
Singleton 单例模式
问什么要试用 Singleton
Singleton 模式保证产生单一实例,就是说一个类只产生一个实例。试用 Singleton 有两个原因
- 是因为只有一个实例,可以减少实例频繁创建和销毁带来的资源消耗。
- 是当多个用户试用这个实例的时候,便于进行统一控制(比如打印机对象)。
前者是性能需求,后者是功能需求。
饿汉式 Singleton
public class HungrySingleton {private static HungrySingleton instance = new HungrySingleton();private HungrySingleton() {}public static HungrySingleton getInstance() {return instance;}
}
注意:一定要有私有的构造函数,保证实例只能通过getInstance()
方法获得。
尽量使用饿汉式构造单实例。单例中的成员变量是多线程重用的,可能会产生意想不到的结果,因此尽量将单例设计为无状态对象(只提供服务,不保存状态)。
饿汉式 Singleton 的问题是,应用一启动就加载对象进内存,就算从来未被用过。
懒汉式 Singleton
publci class LazySingleton {private static LazySingleton instance = null;private LazySingleton() {}public static synchronized LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
注意: getInstance()
的修饰符 synchronized
一定要加上,否则可能会产生多重实例。
懒汉式Singleton解决了饿汉式Singleton,当调用的时候才去加载对象到内存。但是引发了另外一个性能问题,每次访问对象都要加锁。
提升性能的 懒汉式 Singleton
publci class LazySingleton {private static LazySingleton instance = null;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = LazySingleton.buildInstance();}return instance;}private static synchronized LazySingleton buildInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
只有当对象为null
的时候,才去加锁创建对象。
适配器模式
适配器的作用:
系统需要使用现有的类,而这个类的接口与我们所需要的不同。
- 例如: 我们需要对
List
进行排序,但是我们需要一个 Sortable 接口,原有的List
接口不能满足要求。
类的适配器
由于原 Sortable
接口和 ArrayList
不兼容,只好定义一个 NewSortable
public class Sortable<T> extends ArrayList<T> implements NewSortable<T> {public T getElement(int i) {return get(i);}public void setElement(int i, T o) {set(i, o);}
}public interface NewSortalbe<T> {int size();T getElement(int i);void setElement(int i, T o);
}
对象适配器
public class ListSortable<T> implements Sortable<T> {private final List<T> list;public ListSortable(List<T> list) {this.list = list;}public int size() {return list.size();}public T get(int i) {return list.get(i);}public void set(int i, T o) {list.set(i, o);}
}
适配器的应用
JDBC Driver
- 是对具体数据库的适配器
- 例如,将 Oracle 适配到 JDBC 中
JDBC-ODBC Bridge
- 是将 Windows ODBC 适配到 JDBC 接口中
注意:以上信息如有侵权,请联系作者删除,谢谢。
极客大学架构师训练营 框架开发 设计原则 设计模式 反应式编程框架 上课总结 第五课相关推荐
- 可复制领导力 - 极客大学架构师训练营 架构师老A
说明 分享人: 架构师老A 分享主题:<可复制领导力> 分享提纲: 个人能力成长阶梯 东西方领导力差异 管理者角色认知 架构师老A自我介绍 老A亲爱的老师们,同学们,大家好晚上,今晚由我给 ...
- 极客大学架构师训练营大作业
大作业 背景 产品需求 技术方案建议 练习要求 用例图 泳道图 部署图 时序图 用户下单&支付 快递员位置上报 系统派单 订单状态图 背景 产品需求 技术方案建议 练习要求 用例图 说明: ● ...
- 极客大学产品经理训练营:数据分析与商业分析,商业分析到业务分析 第18课总结
讲师:邱岳 1. 产品经理眼中的利润.成本.收入 利润 = 收入 - 成本 奶茶利润率极高,达到60%左右.但是奶茶盈利比较难. 所有买水的产品利润率都极高,比如可口可乐,咖啡,奶茶等. 案例:有个面 ...
- 极客大学产品经理训练营 解决方案的设计与积累 第6课总结
说明 讲师:邱岳(二爷) 1. 解决方案 解决方案的前提是明确了 利益相关者 和 待解决的问题 出解决方案是产品经理的天职,不要直接转发 注意 X-Y Problem,核心关注 X 大量的练习/模仿/ ...
- 极客大学产品经理训练营 产品文档和原型 作业4
作业 [本周作业]写一个用例,挑一个:你自己的产品 / 你喜欢的产品 / [拍东西]发起拍卖/ [知识星球]加入星球/ [极客时间]购买课程: 1. 标题作者修改历史 标题:[极客时间]购买课程 作者 ...
- 极客大学产品经理训练营:业务流程与产品文档 第11课总结
讲师:邱岳 1. 原型图 1.1 手绘图 + Scanner Pro 1.2 线框图 1.3 高保真产品图 1.4 做原型图的目的 坍缩:规划时梦到自己成了乔布斯,赶紧画个图让自己冷静冷静: 具体:具 ...
- 极客大学产品经理训练营:产品文档和原型咋弄 - 流程图 第9课总结
讲师:邱岳 1. 图的意义 流程图.活动图.时序图.状态图,本次聚焦于过程和行为描述. 提效.宏观.点睛. 梳理思路 用例:做什么? 流程图:怎么做? 2. 流程图.活动图.时序图 3. 动手画 – ...
- 极客大学产品经理训练营 极客时间购买课程-大作业
1. 标题作者修改历史 标题:[极客时间]购买课程 作者 历史 时间 易筋 创建 2021-01-09 易筋 添加购买流程图6 2021-03-02 易筋 添加购买时序图7 2021-03-16 2. ...
- Apache架构师的30条设计原则!
点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 作者:Srinath 来源:ImportSource 本文作者叫 Srinath,是一位科学家 ...
- 极客大学产品经理训练营:业务架构与概念模型 第10课总结
讲师:邱岳 1. 什么是状态图 系统中的概念或对象随着一些事件的发生,改变了状态,通常这个状态比较多.比较复杂时,我们需要用状态图来表示他们的边界,以及触发状态转换的活动. 2. 动手画 – 员工状态 ...
最新文章
- Python 常见语法逻辑错误收集
- 图层几何学 -- iOS Core Animation 系列二
- matlab ask函数,matlab函数大全(非常实用)
- c 数据压缩算法_CCSDS图像压缩算法之我见(一)
- python 管道队列_关于python:Multiprocessing-管道与队列
- 信息学奥赛一本通C++语言——1128:图像模糊处理
- SSH-struts2的异常处理
- [通信] ITU-T G.729 8kb/s CS—ACELP简介
- mysql转储表_Mysql导出表结构及表数据 mysqldump用法
- 百战程序员JavaWeb系列教程-监听器视频教程
- 在线解析短视频去水印工具
- 人生就是一个领域,一份爱,一杯茶
- 信通方恒资产评估快讯 -《中国矿业》矿业综述 - 2021年国内外油气资源形势分析及展望
- 如何进行测试用例评审
- 【直击DTCC】自然语言技术在文智趋势分析产品的应用
- 【26】地图可视化:基于 Echarts + Flask 的动态实时地图组件 - 点气泡流向组合区域三级下钻地图
- 随机森林python
- 磁力链接搜索网站研究心得!
- 电厂/矿井UWB室内定位解决方案
- 985毕业,半路出家28岁进军Java,坚持了三年现如今年薪36W+,也不算辜负自己!
热门文章
- base64编码 vba_[VBA]Base64编码和Base64解码
- python functiontools_Python: Tools
- php空格占几个字符,一个空格几个字符?
- 1.VUE 安装以及vue.js下的第一个hello world
- (Windows)Scala学习3--列表、数组
- iOS开发UI篇--仿射变换(CGAffineTransform)使用小结
- Error:Execution failed for task ':app:lint'.
- 批处理命令调用WINRAR对文件进行压缩
- xampp启动遇到的小问题
- Linux 数据重定向