设计模式 & 重构

用户头像
Amy
关注
发布于: 2020 年 06 月 24 日

1. 反应式编程框架 Flower

1.1. 程序是如何运行又如何崩溃

系统为每个用户请求分配一个线程,当程序内部因为访问数据库等原因造成线程阻塞时,线程无法释放去处理其他请求,这样就会造成请求堆积,不断消耗资源,最终导致程序崩溃。

1.2. 反应式编程

反应式编程本质上是一种异步编程方案,在多线程(协程)、异步方法调用、异步 I/O 访问等技术基础之上,提供了一整套与异步调用相匹配的编程模型,从而实现程序调用非阻塞、即时响应等特性,即开发出一个反应式的系统,以应对编程领域越来越高的并发处理需求。



核心:异步执行、消息驱动

1.3. Flower框架





https://github.com/zhihuili/flower.git



Flower是一个构建在Akka上的反应式微服务框架,开发者只需要针对每一个细粒度的业务功能开发一个Service服务,并将这些Service按照业务流程进行可视化编排,即可得到一个反应式系统。



2. 设计模式

我理解的设计模式,就是前辈们总结的,解决某一方面问题的套路。



对于设计模式,简直是又爱又很。在工作中运用了设计模式,应对不停变更的需求也不需要加班了。但是也遇到过有同事乱改代码,破坏原本的设计模式,导致生产环境出现异常,造成客户经济损失。



因此,无论你是否在工作中应用设计模式,都要把它学好。要不然别人的代码都不一定看不懂。更严重的是以为自己看懂,实际上是看不懂,然后乱改代码。这种情况实在太可怕了。



设计模式是双刃剑,如果用得好,就算产品经理天天改需求,都不用再加班了。如果用不好,有可能会导致直接的经济损失。

2.1. 一个设计模式的四个部分

  • 模式的名称 —— 由少量的字组成的名称,有助于我们表达我们的设计。

  • 待解问题 —— 描述了何时需要运用这种模式,以及运用模式的环境(上下文)。

  • 解决方案 —— 描述了组成设计的元素(类和对象)、它们的关系、职责以及合作。但这种解决方案是抽象的,它不代表具体的实现

  • 结论 —— 运用这种方案所带来的利和弊。主要是指它对系统的弹性、扩展性、和可一致性的影响。



2.2. 几种常见的设计模式

2.2.1. 简单工厂



把对象的创建转移到工厂中,由工厂统一创建

2.2.2. 单例



单例保证产生单一实例,就是说一个类只产生一个实例。

优点:

  • 因为只有一个实例,可以减少实例频繁创建和销毁带来的资源消耗

  • 当多个用户使用这个实例的时候,便于进行统一控制。

用C#语言实现单例:



方法1:双重 if + lock



public class Singleton
{
/// <summary>
/// 1. 私有化构造函数,不让其他人new
/// </summary>
private Singleton()
{
}
/// <summary>
/// 3. 全局唯一静态变量,重用这个变量
/// </summary>
private static volatile Singleton _Singleton = null; // volatile 促进线程安全,让线程按顺序操作
// 4. 锁
private static object Singleton_Lock = new object();
/// <summary>
/// 2. 公开的静态方法提供对象实例
/// </summary>
/// <returns></returns>
public static Singleton CreateInstance()
{
if (_Singleton == null)
{
// 保证任意时刻只有一个线程进入lock范围
// 限制了并发,尤其是 _Singleton 已经被初始化之后
lock (Singleton_Lock)
{
if (_Singleton == null)
{
_Singleton = new Singleton();
}
}
}
return _Singleton;
}
}



方法2:静态构造函数

/// <summary>
/// 饿汉式:只要使用类就会被构造
/// </summary>
public class Singleton
{
/// <summary>
/// 静态构造函数:由CLR保证,程序第一次使用这个类型前被调用,且只调用1次
/// </summary>
static Singleton()
{
_Singleton = new Singleton();
}
private static Singleton _Singleton = null;
public static Singleton CreateInstance()
{
return _Singleton;
}
}



2.2.3. 适配器模式



适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。

不推荐使用类的适配器,一般使用对象的适配器。



适配器的应用:

JDBC Driver

  • 是对具体数据库的适配器

  • 例如,将 Oracle 适配到 JDBC 中



JDBC-ODBC Bridge

  • 是将 Windows ODBC 适配到 JDBC 接口中

2.2.4. 模板方法

模板方法模式是扩展功能的最基本模式之一

  • 它是一种“类的行为模式”



它是通过“继承”的方法来实现扩展

  • 基类负责算法的轮廓和骨架

  • 子类负责算法的具体实现



组合 vs 继承

  • 基于 “继承”的模板方法比“组合”更容易实现

  • 在很多情况下,可以适当使用这种方法



模板方法的形式



抽象方法:

  • protected abstract void step1();

  • 强制子类实现该步骤



具体方法:

  • protected void doSomething(){ ... }

  • 子类不需要覆盖,但也可以覆盖之

  • 如果想明确告诉子类 “不需要覆盖它”,组好表明:final



钩子方法:

  • protected void setUp(){}

  • 空的实现(缺省适配器模式)

  • 子类可选择性地覆盖之,以便在特定的时机做些事。



何时使用模板方法



重构系统的时候

  • 将一个大方法打破,变成多个可扩展的步骤。

  • if/elseswitch语句改换成多态性。



模板方法可能产生的问题:

  • 将抽象算法和具体步骤耦合在一起,不能独立演化

  • 造成类的数量很多、类的层次很深



2.2.5. 策略模式



策略模式是扩张功能的另一种最基本的模式。

它是一种“对象的行为模式”。

它是通过“组合”的方式来实现扩展。



什么时候使用策略模式



系统需要在多种算法中选择一种

重构系统时,

  • 将条件语句转换成对于策略的多态性调用



优点(对比模板方法)

  • 将使用策略的人与策略的具体实现分离

  • 策略对象可以自由组合



可能存在的问题

策略模式仅仅封装了“算法的具体实现”,方便添加和替换算法。但它并不关心何时使用何种算法,这个必须由客户端来决定。

2.2.6. 组合模式

组合模式是一种“对象的结构模式”

将对象组合成树形结构以表示 “部分 - 整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。



何时使用组合模式:

  • 需求中是体现部分与整体层次的结构时

  • 希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时

2.2.7. 装饰器模式

装饰器模式是一种“对象的结构模式”



作用:

  • 在不改变对客户端的接口的前提下(对客户端透明)

  • 扩展现有对象的功能



装饰器 vs 模板 vs 策略

  • 装饰器保持对象的功能不变,扩展其外围的功能

  • 模板方法和策略模式则保持算法的框架不变,而扩展其内部的实现



装饰器 vs 继承

  • 都可以用来扩展对象的功能

  • 但装饰器是动态的,继承时静态的

  • 装饰器可以任意组合



2.3. 编程框架中的设计模式

2.3.1. Junit中的设计模式

JUnit 是一个 Java 单元测试框架,开发者只需要继承 JUnit 的 TestCase,开发自己的测试用例类,通过 JUnit 框架执行测试,就得到测试结果。



实现一个单元测试的步骤

创建测试类,从 TestCase 派生

初始化

覆盖基类的方法:protected void setUp()



清除环境

覆盖基类的方法:protected void tearDown()



书写测试方法

命名规则:public void testXyz()

2.3.2. Java Servlet 中的模板方法



用户头像

Amy

关注

还未添加个人签名 2018.06.10 加入

还未添加个人简介

评论

发布
暂无评论
设计模式&重构