极客大学架构师训练营 框架开发 模式与重构 JUnit、Spring、Hive核心源码解析 第6课
说明
讲师:李智慧
JUnit 中的设计模式
如何写单元测试
public class BubbleSorterTests extends TestCase {
private Integer[] array;
private Sorter sorter;
protected void setUp() {
array = new Integer[] { 5, 4, 9, 7, 6, 3, 8, 1, 0, 2};
sorter = new BubbleSorter();
}
public void testSort() {
Sortable sortable = new ArraySortable(array);
Comparator comparator = new IntegerComparator();
sorter.sort(sortable, comparator);
for (int i = 0; i < 10; i++ ) {
assertEquals(i, array[i].intValue());
}
}
}
实现一个单元测试的步骤
创建测试类, 从 TestCase 派生
初始化
覆盖基类的方法:
消除环境
覆盖基类的方法:
书写测试方法
命名规则:
JUnit 单元测试是如何执行的?
public abstract class TestCase extends Assert implements Test {
public boid runBare() throws Throwable {
Throwable exception = null;
setUp();
try {
runTest();
} catch (Throwable running) {
exception = running;
} finally {
try {
tearDown();
} catch (Throwable tearingDown) {
if (exception == null) exception = tearingDown;
}
}
if (exception != null) throw exception;
}
protected void runTest() throws Throwable {
// 利用动态机制调用 testXyz()
}
protected void setUp() throws Exception { }
protected void tearDown() throws Exception { }
}
JUnit 单元测试的执行
Idea 中运行单元测试通过的图片。

JUnit 单元测试的执行时序图

这里用到了三个策略模式:
模板方法模式(Template Method)
模板方法模式是扩展功能的最基本模式之一
它是一种 ”类的行为模式“
它是通过 ”继承“ 的方法来实现扩展
基类负责算法的轮廓和骨架
子类负责算法的具体实现
组合 vs. 继承
基于 ”继承“ 的模板方法比 ”组合“ 更容易实现
在很多情况下,可以适当使用这种模式。
模板方法的形式
抽象方法
强制子类实现该步骤。
具体方法
子类不需要覆盖,但也可以覆盖之。
如想明确告诉子类 ”不要覆盖它“,最好标明:
钩子方法
空的实现(缺省适配器模式)
子类可选择性地覆盖之,以便在特定的时机做些事。
Java Servlet 中的模板方法

Java Servlet中有两个模板方法
测试 Sortable
public abstract class SortableTests extends TestCase {
protected Sortable sortable;
protected void setUp() {
Integer[] data = new Integer[10];
for (int i = 0; i < 10; i++) {
data[i] = i;
}
sortable = createSortable(data);
}
protected abstract Sortable createSortable(Integer[] data);
public final void testGet() {
for (int i = 0; i < 10; i++ ) {
assertEqual(i, sortable.get(i).intValue());
}
try {
sortable.get(-1);
fail();
} catch (RuntimeException e) {
}
}
public final void testSet() {
for (int i = 0; i < 10; i++) {
sortable.set(i, 100);
assertEquals(100, sortable.get(i).intValue());
}
try {
sortable.set(-1, 999);
fail();
} catch (RuntimeException e) {
}
try {
sortable.set(10, 999);
fail();
} catch (RuntimeException e) {
}
}
public final void testSize() {
assertEquals(10, sortable.size());
}
}
测试 ArraySortable
public class ArraySortableTests extends SortableTests {
@Override
protected Sortable createSortable(Integer[] data) {
List list = Arrays.asList(data);
return new ListSortable(list);
}
}
测试 ListSortable
public class ListSortableTests extends SortableTests {
@Override
protected Sortable createSortable(Integer[] data) {
return new ArraySortable(data);
}
}
测试排序程序类图

策略模式(Strategy)
策略模式是扩展功能的另一种最基本的模式
它是一种 ”对象的行为模式“
它是通过 ”组合“ 的方法来实现扩展

什么时候使用策略模式?
系统需要在多种算法中选择一种
重构系统时
将条件语句转换成对于策略的多态性调用
策略模式的优点(对比模板方法)
将使用策略的人与策略的具体实现分离
策略对象可以自由组合
策略模式可能存在的问题:
策略模式仅仅封装了 ”算法的具体实现“,方便添加和替换算法。但它并不关心何时使用何种算法,这个必须由客户端来决定。
策略模式和模板方法的结合

参数化的单元测试
public abstract class ComparatorTests extends TestCase {
protected T o1;
protected T o2;
protected boolean ascending;
protected boolean isBefore;
public ComparatorTests(T o1, T o2, boolean ascending, boolean isBefore) {
super("testIsBefore");
this.o1 = o1;
this.o2 = o2;
this.ascending = ascending;
this.isBefore = isBefore;
}
public void testIsBefore() {
assertEquals(isBefore, createComparator(ascending).isBefore(o1, o2));
}
protected abstract Comparator createComparator(boolean ascending);
}
public class IntegerComparatorTests extends ComparatorTests {
public static Test suite() {
TestSuite suite = new TestSuite("IntegerComparatorTests");
suite.addTest(new IntegerComparatorTests(1, 1, true, false));
suite.addTest(new IntegerComparatorTests(1, 2, true, true));
suite.addTest(new IntegerComparatorTests(2, 1, true, false));
suite.addTest(new IntegerComparatorTests(1, 1, false, false));
suite.addTest(new IntegerComparatorTests(1, 2, false, false));
suite.addTest(new IntegerComparatorTests(2, 1, false, true));
return suite;
}
public IntegerComparatorTests(Integer o1, Integer o2, boolean ascending, boolean isBefore) {
super(o1, o2, ascending, isBefore);
}
@Override
protected Comparator createComparator(boolean ascending){
}
}
上述代码生成一个 ”测试包“

生成更复杂的 ”测试包“
public class AllTests {
public static Test suite() {
TestSuite suite = new TestSuite("sort");
suite.addTestSuite(BubbleSorterTests.class);
suite.addTestSuite(InsertionSorterTests.class);
suite.addTestSuite(ArraySorterTests.class);
suite.addTestSuite(ListSorterTests.class);
suite.addTestSuite(IntegerComparatorTests.class);
suite.addTestSuite(ComparableComparatorTests.class);
return suite;
}
}

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

组合模式的应用
文件系统
AWT 控件

测试排序程序的性能
冒泡排序和插入排序,谁更快?
这种测试必须重复多次(如10,000次)侧能比较准确地计算出性能。
如何让 BubbleSorterTests 和 InsertionSorterTests 重复运行多次,而不需要修改他们的代码?
如何计算时间?
运用 JUnit 扩展包中的辅助类:
性能测试程序
public class PerformanceTests extends TestSetup {
private long start;
private int repeat;
public PerformanceTests() {
super(new RepeateedTest(test, repeat));
this.repeat = repeat;
}
public void setUp() throws Exception {
start = System.currentTimeMillis();
}
protected void tearDown() throws Exception {
long duration = System.currentTimeMillis() - start;
System.out.printf("%s repeated %d times, takes %d ms\n", getTest(), repeat, duration);
}
public static Test suite() {
TestSuite suite = new TestSuite("performance");
Test bubbleTests = new TestSuite(BubbleSorterTests.class);
Test insertionTests = new TestSuite(InsertionSorterTests.class);
suite.addTest(new PerformanceTests(bubbleTests, 10000));
suite.addTest(new PerformanceTests(insertionTests, 10000));
return suite.
}
}
性能测试核心源码
public class TestDecorator extends Assert implements Test {
protected Test fTest;
public TestDecorator(Test test) {
fTest = test;
}
@Override
public void run(TestResult result) {
for (int i = 0; i < fTimesRepeat; i++) {
if (int i = 0; i < fTimesRepeat; i++) {
if (result.shouldStop()) {
break;
}
}
super.run(result);
}
}
}
装饰器模式(Decorator)

装饰器模式
是一种 ”对象的结构模式“
装饰器模式的作用
在不改变对客户端的接口的前提下(对客户端透明)
扩展现有对象的功能
思考 PerformanceTests 的客户端是指谁?
装饰器模式也被笼统地称为 ”包装器“(Wrapper)
适配器也被称作 ”包装器“,区别在于适配器是转换成另一个接口,而装饰器是保持接口不变。
包装器形成一条 ”链“。

装饰器模式 ”包装器“例子(Wrapper)
明月装饰了梦装饰了你
梦装饰了明月装饰了你
public interface Anything {
void exe();
}
public class Moon implements Anything {
private Anything a;
public Moon(Anything a) {
this.a = a;
}
public void exe() {
System.out.print("明月装饰了");
a.exe();
}
}
public class Dream implements Anything {
private Angthing a;
public Dream(Anything a) {
this.a = a;
}
publci void exe() {
System.out.print("梦装饰了");
a.exe();
}
}
public class You implements Anything {
private Angthing a;
public You(AnyThing a) {
this.a = a;
}
public void exe() {
System.out.print("你");
}
}
public class MainClass {
public static void main(String[] args) {
Anything t = new Moon(new Dream(new You(null)));
t.exe();
// 明月装饰了梦装饰了你
Anything t1 = new Dream(new Moon(new You(null)));
t1.exe();
// 梦装饰了明月装饰了你
}
}
装饰器模式的优缺点
装饰器和模板方法、策略模式的比较
装饰器保持对象的功能不变,扩展其外围的功能。
模板方法和策略模式则保持算法的框架不变,而扩展其内部的实现。
装饰器和继承的比较
都可以用来扩展对象的功能
但装饰器是动态的,继承是静态的
装饰器可以任意组合
☞ 但这也使装饰器更复杂,有可能会组合出荒谬的结果
装饰器模式的应用
Java Servlet 中的应用
/
/
同步化装饰器
取代原先的 、 等同步类。
Java I/O 类库简介
核心 - 流, 即数据的有序排列,将数据从源送达目的地。
流的种类
☞ 、 - 代表 流 (八位字节流)
☞ 、 - 代表 流( 字符流)
流的对称性
☞ 输入 - 输出对称
☞ - 对称
☞ 因此我们只要学习任意一种流,就可以基本了解其它所有的流。
依赖注入 DI 与控制反转 IOC

DI、 IOC 的应用例子
public class Client {
private UserService userService;
public setUserService(UserService userService) {
this.userService = userService;
}
}
DI、 IOC 的核心源码
private static void parseBeanElement() throws Exception {
String id = beanElement.attributeValue("id");
String clsName = beanElement.attributeValue("class");
// 获取 Class 对象
Class> cls = Class.forName(clsName);
// 直接调用无参数构造函数,实例化一个对象
Object beanObj = cls.getDeclaredConstructor().newInstance();
beanMap.put(id, beanObj);
// 获取属性节点,并调用 setter 方法设置属性
List subElement = beanElement.elements();
for (Element subElem: subElemList) {
// 获取属性名称
String name = subElem.attributeValue("name");
// 获取属性值
String ref = subElem.attributeValue("ref");
Object refObj = beanMap.get(ref);
// 根据属性名称构造 setter 方法名: set + 属性首字母大写 + 属性其它字符,例: setUserDao
String methodName = "set" + (char)(name.charAt(0) - 32) + name.substring(1);
// 获取 Method 对象
Method method = cls.getDeclaredMethod(methodName, refObj.getClass().getInterface()[0]);
// 调用 setter 方法,设置对象属性
method.invoke(beanObj, refObj);
}
}
Spring 中的单例模式
private final Map singletonObjects = new HashMap();
protected Object getSingleton(String beanName) {
// 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 如果为空,则锁定全局变量并进行处理。
synchronized (this.singletonObjects) {
// 调用工厂的 getObject 方法
singletonObject = singletonFactory.getObjet();
// 记录在缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
单例怎么获取:
Spring MVC 模式
@RestController
@RequestMapping("/user/")
public class QueryUserController extends FlowerController {
@Autowired
OrderNoService orderNoService;
@RequestMapping(value = "query")
public void hello(String userId) {
logger.info("gain request: {}", userId);
doProcess(userId);
}
}

public boolean handle(ServletRequest req, ServletResponse res) {
String uri = ((HttpServletRequest) req).getRequestURI;
Object[] parameters = new Object[args,length];
for (int i = 0; i < args.length; i++) { //
parameters[i] = req.getParameter(args[i]);
}
Object ctl = controller.newInstance(uri);
Object response = method.invoke(ctl, parameters);
res.getWriter().println(response.toString());
return true;
}
SQL in Hadoop Eco-system
Hive
Impala
Presto
Phoenix
Shark
Hive Architecture

开源地址:
An analytical SQL engine for MapReduce

Exists Case Study
SQL 转换为语法树

复杂的问题通过装饰者模式变得简答

transformer 把Oracle SQL转换为join
generator 把Oracle SQL转换为Hive SQL
开闭原则
难的问题解决了,后人就比较容易理解了。
比如爱因斯坦的相对论,现在高中生都在学习。
牛顿力学,现在初中生都在学习。
复杂的问题理解了,就算前任理解了,后人理解还是比较难理解复杂的问题。
注意:以上信息如有侵权,请联系作者删除,谢谢。