极客大学架构师训练营 框架开发 模式与重构 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 派生

初始化

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

消除环境

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

书写测试方法

  • 命名规则: public void testXyz()

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 单元测试的执行时序图
在这里插入图片描述

这里用到了三个策略模式:

  1. Eclipse定义了接口,策略的接口,策略的实现。定义一个plugin的规范。显示有多少个用例通过,多少个用例失败。
  2. Eclipse 调用runBare方法,调用TestCase。
  3. TestCase只有一个,实现有多个,XyzTests有多个。

模板方法模式(Template Method)

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

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

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

  • 基类负责算法的轮廓和骨架
  • 子类负责算法的具体实现

组合 vs. 继承

  • 基于 ”继承“ 的模板方法比 ”组合“ 更容易实现
  • 在很多情况下,可以适当使用这种模式。

模板方法的形式

抽象方法

  • protected abstract void step1();
  • 强制子类实现该步骤。

具体方法

  • protected void doSomething() { ... }
  • 子类不需要覆盖,但也可以覆盖之。
  • 如想明确告诉子类 ”不要覆盖它“,最好标明: final

钩子方法

  • protected void setUp() { }
  • 空的实现(缺省适配器模式)
  • 子类可选择性地覆盖之,以便在特定的时机做些事。

Java Servlet 中的模板方法

在这里插入图片描述
Java Servlet中有两个模板方法

  1. 模板方法: service() 判断使用哪种方式处理网络请求GET, POST, PUT等。
  2. Servlet interface也是个模板方法,因为Servlet的生命周期方法,一定是固定的。

测试 Sortable

public abstract class SortableTests extends TestCase {
	protected Sortable<Integer> 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<Integer> 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<Integer> createSortable(Integer[] data) {
		List<Integer> list = Arrays.asList(data);
		return new ListSortable<Integer>(list);
	}
}

测试 ListSortable

public class ListSortableTests extends SortableTests {
	@Override
	protected Sortable<Integer> createSortable(Integer[] data) {
		return new ArraySortable<Integer>(data);
	}
}

测试排序程序类图

在这里插入图片描述

策略模式(Strategy)

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

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

它是通过 ”组合“ 的方法来实现扩展
在这里插入图片描述

什么时候使用策略模式?

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

重构系统时

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

策略模式的优点(对比模板方法)

  • 将使用策略的人与策略的具体实现分离
  • 策略对象可以自由组合

策略模式可能存在的问题:

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

策略模式和模板方法的结合

在这里插入图片描述

参数化的单元测试

public abstract class ComparatorTests<T> 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<T> createComparator(boolean ascending);

}

public class IntegerComparatorTests extends ComparatorTests<Integer> {
	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<Integer> 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 扩展包中的辅助类:

  • junit.extensions.TestSetup
  • junit.extensions.RepeatedSetup

性能测试程序

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 中的应用

  • HttpServletRequest / HttpServletRequestWrapper
  • HttpServletResponse / HttpServletResponseWrapper

同步化装饰器

  • Collections.synchronizedList(list)
  • 取代原先的 VectorHashtable 等同步类。

Java I/O 类库简介

  • 核心 - 流, 即数据的有序排列,将数据从源送达目的地。
  • 流的种类
    InputStreamOutputStream - 代表 byte 流 (八位字节流)
    ReaderWriter - 代表 char 流(Unicode 字符流)
  • 流的对称性
    ☞ 输入 - 输出对称
    Byte - Char 对称
    ☞ 因此我们只要学习任意一种流,就可以基本了解其它所有的流。

依赖注入 DI 与控制反转 IOC

在这里插入图片描述

DI、 IOC 的应用例子

public class Client {
	private UserService userService;
	public setUserService(UserService userService) {
		this.userService = userService;
	}
}
<bean id="userService" class="com.hello.UserDaoImpl">
	<property name="userDao" ref="userDao" />
</bean>
<bean id="client" class="com.hello.Client">
	<property name="userService" ref="userService" />
</bean>

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<Element> 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);
}

单例怎么获取: beanMap.get(ref)

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

在这里插入图片描述
开源地址:
https://github.com/zhihuili/project-panthera-ase/tree/master/ql/src/java/org/apache/hadoop/hive/ql/parse/sql

An analytical SQL engine for MapReduce

在这里插入图片描述

Exists Case Study

SQL 转换为语法树
在这里插入图片描述

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

在这里插入图片描述
transformer 把Oracle SQL转换为join
generator 把Oracle SQL转换为Hive SQL

开闭原则

难的问题解决了,后人就比较容易理解了。
比如爱因斯坦的相对论,现在高中生都在学习。
牛顿力学,现在初中生都在学习。

复杂的问题理解了,就算前任理解了,后人理解还是比较难理解复杂的问题。

注意:以上信息如有侵权,请联系作者删除,谢谢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章