代码重构

用户头像
escray
关注
发布于: 2020 年 10 月 03 日
代码重构

3.1 设计模式:使用设计模式优化排序工具包的设计



设计模式是一种可重复使用的解决方案。



  • 模式的名称

  • 待解决问题

  • 解决方案

  • 结论



有一个问题,写 Ruby 程序是否能够用到设计模式?感觉不像 Java 那么明显(多态、继承)。



  1. 简单工厂 SingleFactory

  2. 单例 Singleton

  3. 适配器 Adapter

  4. 模板方法 Template Method

  5. 策略 Strategy

  6. 组合 Composite

  7. 装饰器 Decorator

  8. 依赖注入 DI

  9. MVC



排序问题



  • 排序器:interface Sorter,BubbleSorter, InsertionSorter

  • 容器:interface Sortable,ArraySortable, InsertionSortable

  • 比较器:interface Comparator,ComparableComparator,IntegerComparator



如何创建一个对象?



简单工厂模式



简单工厂模式



public class SorterClient {
public static void main(String[] args) {
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);
}
}
class SorterFactory {
public static <T> Sorter<T> getSorter() {
return new BubbleSorter<T>();
}
}



应用程序(Client)不依赖 Sorter 的具体实现,满足开闭原则,但是 Factory 不满足,增加 Sorter 需要修改 Factory。



改进二,通过反射去获得类。



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;
}
@SuppressWarnings("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);
}
}
}



通过配置文件,解决了工厂本身的开闭原则。



我之前也能够想到采用配置文件的方式来实现开闭原则,但是确实没怎么用过反射



简单工厂是其他设计模式的基础 为什么这么讲?



3.2 设计模式:Singleton单例模式



为什么要使用 Why



  • 性能:只有一个实例,减少创建和销毁带来的资源消耗

  • 业务:多个用户使用一个实例



饿汉模式,提前创建实例



public class Singleton {
private Singleton() {
}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}



懒汉模式



class Singleton2 {
private Singleton2() {
}
private static Singleton2 instance = null;
public static synchronized Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}



synchronized 多个线程,同步等待



一般推荐第一种(饿汉模式)



单例中的成员变量是多线程重用的,可能会产生意想不到的结果,因此尽量将单例设计为无状态对象(只提供服务,不保存状态)



适配器模式 Adapter



适配器模式



  • 类的适配器:继承的方式

  • 对象的适配器:组合的方式



public class Adapter {
}
interface NewSortable<T> {
int size();
T getElement(int i );
void setElement(int i, T o);
}
// Class Adapter
class SortableList<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);
}
}
// Object Adapter
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 接口



3.3 JUnit中的设计模式



模板方法模式 Template Method



类的行为模式,父类中定义模板方法(抽象,轮廓和骨架),子类中实现(算法),通过“继承”的方法来实现扩展



三种形式:



  • 抽象方法 protected abstract void step1();  父类定义抽象方法,子类强制实现

  • 具体方法 protected void doSomthing() { … }; 父类定义具体方法,子类选择性覆盖

  • 钩子方法 protected void setUp() { } 父类定义空方法,子类可以选择性覆盖



// 测试 ArraySortable
public class ArraySortableTests extends SortableTests {
@Override
protected Sortable<Integer> createSortable(Integer[] data) {
return new ArraySortable<Integer>(data);
}
}
// 测试 ListSortable
public class ListSortableTests extends SortableTests {
@Override
protected Sortable<Integer> createSortable(Integer[] data) {
List<Integer> list = Arrays.asList(data);
return new ListSortable<Integer>(list);
}
}



这两段代码在课件上放反了,老师讲解的时候也没有注意,作为 Java 菜鸟,我琢磨了半天,以为有什么玄机。



策略模式 Strategy



策略模式



对象的行为模式,通过组合的方法来实现扩展



重构系统时,将条件语句转换成为对策略的多态性调用



策略模式只封装“算法的具体实现”,不关心何时使用,由客户端决定



组合模式 Composite



组合模式



对象的结构模式



测试排序程序的性能



装饰器模式 Decorator



装饰器模式



如果只看图片的话,感觉装饰器模式和前面的组合模式有点像,都有迭代关系。



迭代装饰



装饰器模式是用来写诗的 —— 极客时间专栏留言



对象结构模式



  • 对客户端透明,不改变对客户端的接口

  • 扩展现有对象功能



Wrapper 包装器



装饰器 vs 模板方法



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

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



装饰器 vs 继承



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

  • 装饰器是动态,继承是静态

  • 装饰器可以任意组合



装饰器的应用



Java I/O 类库



核心:流,数据的有序排列,将数据从源送达目的地



流的种类



  • Byte 流(八位字节流):InputStream、OutputStream

  • Char 流(Unicode 字符流):Reader、Writer



流的对称性



  • 输入 vs. 输出

  • Byte vs. Char



只要学习任意一种流,就基本可以了解其他所有的流。



这一部分算是意外收获,之前对于流的概念一直有点模糊,直到看到这里,Byte 流和 Char 流,豁然开朗。



3.5 Spring中的设计模式



依赖注入 DI 与 控制反转 IoC



依赖注入和控制反转



A 对象不要创建所依赖的 B 对象,由外部去创建并且注入。



依赖注入 DI 和 MVC 好像都不在 GoF 23 种设计模式之中,不过也确实算是常见的设计模式。



另外 Spring Boot 是不是已经放弃了 MVC 模式?(不会 Spring 的菜鸟)



3.6 设计模式案例:Intel 大数据 SQL 引擎 & Panthera 设计模式



Hive – THE Data Warehouse for Hadoop



  • HiveQL: a SQL-like query language (subset of SQL with extensions)

  • Significantly lowers the barrier to MapReduce

  • Still large gaps with full analytic SQL support

  • Multiple-table SELECT statement, subquery in WHERE and HAVING clauses, etc.



Project Panthera ASE



Our open source efforts to enable better analytics capabilities on Hadoop



  • Built on top of Hive

  • Provide full SQL support for OLAP

  • Better integration with existing infrastructure using SQL



Hive Architecture



Hive Architecture



An analytical SQL engine for MapReduce



SQL engine



Panthera 代码解析



从单一职责原则开始重构



Translator



  • generator 生成 Hive 支持的 AST

  • transformer 转换 SQL AST



TransformBuilder



transformer 装饰器模式



这段段代码真的没有问题么?功能上肯定没问题,但是似乎不怎么好看。如果不是竖屏显示器,那么很容易就违背了一个类或者方法不超过一屏。



还有一个问题,顺序不重要?



BaseSqlASTTransformer



模板方法 abstract void transform(…)



HiveASTGenerator

https://github.com/zhihuili/project-panthera-ase/blob/master/ql/src/java/org/apache/hadoop/hive/ql/parse/sql/generator/HiveASTGenerator.java



generateHiveAST

https://github.com/zhihuili/project-panthera-ase/blob/master/ql/src/java/org/apache/hadoop/hive/ql/parse/sql/generator/BaseHiveASTGenerator.java



模板方法



LikeGenerator

https://github.com/zhihuili/project-panthera-ase/blob/master/ql/src/java/org/apache/hadoop/hive/ql/parse/sql/generator/LikeGenerator.java



baseProcess

https://github.com/zhihuili/project-panthera-ase/blob/master/ql/src/java/org/apache/hadoop/hive/ql/parse/sql/generator/BaseHiveASTGenerator.java



如果遇到一个新的语法点,那么增加一个对应的 Transformer 就可以



3.7 第三周课后练习



作业一:



  1. 请在草稿纸上手写一个单例模式的实现代码,拍照提交作业。

  2. 请用组合设计模式编写程序,打印输出图 1 的窗口,窗口组件的树结构如图 2 所示,打印输出示例参考图 3。



编程作业



作业二:根据当周学习情况,完成一篇学习总结



看了前两周的优秀学习笔记和作业,发现自己依然是个学渣,不过我还是只打算先做一个简单的作业。



Well done is better than well said

-- Benjamin Franklin



Done is better than perfect.

-- a mantra in Facebook’s "hacker culture"

-- Sheryl Sandberg

发布于: 2020 年 10 月 03 日 阅读数: 16
用户头像

escray

关注

Let's Go 2017.11.19 加入

大龄程序员

评论

发布
暂无评论
代码重构