写一千行重复代码,不如读十行优雅设计的代码。
在 “编程漫谈(十八):编程三境界” 谈到:重复性做一件事,并不一定会促进技艺的提升,反而,有可能导致持续性的退步。每日有所进步(哪怕只有微小的进步),才能促进编程技艺的提升。这种进步,或者来自于简单的代码重构,或者来自于大胆的全局结构重构,或者来自于有挑战性的编程课题,或者来自于设计先导的构思,或者来自于对模型完善性的推敲。只有在重复中渐进地变化、小幅提升、大幅突破,才会收获飞跃性的进步。
要持续进步,就需要持续的输入。没有优质的输入,人就很容易陷入重复性行为而浑然不觉。对于技术人员来说,跳出原有思维和做法的一个有效途径,就是阅读优秀的源代码,汲取其中的设计思想,应用到工作中。
有人一听阅读源代码,想想那密密的几百万行,那数不尽的细节,顿时就想打退堂鼓。我也有这种心理。不过,就像编程一样,阅读源代码也是一种技艺,可以一步步提升的。
源代码可以分为设计与实现。设计更多涉及宏观的布局,核心类的设计、全局控制结构的设计,涉及细节并不多;只有深入到实现中,才会涉及细节。实现自然有实现的乐趣和魅力,设计则更注重“观其大略之美”。
本文着重探讨如何从优秀 Java 源码中汲取好的设计思想。假定读者已经有了一定的源码阅读经历和基本的阅读能力,能够通过阅读源码解决一些日常问题。阅读源代码的基本方法可阅:“解锁优秀源代码的方法与技巧总结(上)”
设计思想主要包括:
软件系统通常由抽象和集成构建。此外,通常会有一些对行为规范的基本实现,称为抽象类,可以供业务方自定义针对具体场景的实现。
要学习源码的设计思想,通常就可以从以下方面着手:
阅读步骤及顺序: 核心接口 -> 主要流程 -> 类交互 -> 抽象类 -> 核心类。实际阅读时,可适当调整。
如果一时读不懂,可以上网去搜索类名(或缩写,比如 AQS)或框架名(SpringBoot),基本上都有人解读过的。 有了这些准备,就可以踏上阅读源码的征途了。
"Hello World" 可以说是程序界新手上路的必经之途。对于 Java 源码阅读,个人特别推荐 Java 集合框架和 Java IO 框架。
Java 集合框架
推荐理由:1. 很实用; 2. “接口-抽象类-实现类”的经典示例之一; 3. 类的交互简单。
Java 集合框架的整体设计如下所示。一张图就搞定了。可见,类图是解读源码设计思想的有力武器之一。
理解 Java 集合框架设计的重点在于:
Java IO 框架
推荐理由:
可阅 “javaIO框架小析”
JUnit4
读懂 Java 集合框架和 IO 框架之后,接下来可以挑战 JUnit4。
推荐理由:1. 功能简单,不涉及复杂的技术和原理; 2. 模板设计模式; 3. 适量而优雅的类交互;4. 一个简洁易用框架的设计考虑。
解读:
public void runBare() throws Throwable {
Throwable exception = null;
this.setUp();
try {
this.runTest();
} catch (Throwable var10) {
exception = var10;
} finally {
try {
this.tearDown();
} catch (Throwable var11) {
if (exception == null) {
exception = var11;
}
}
}
if (exception != null) {
throw exception;
}
}
public TestResult run() {
TestResult result = this.createResult();
this.run(result);
return result;
}
protected void run(final TestCase test) {
this.startTest(test);
Protectable p = new Protectable() {
public void protect() throws Throwable {
test.runBare();
}
};
this.runProtected(test, p);
this.endTest(test);
}
TestSuite & BaseTestRunner & TestRunner: 一组测试用例集的定义和执行。这是在核心的基础上,使之实用化的必要件。具体是利用反射和方法约定,来生成要测试的用例集。BaseTestRunner 是抽象类,定义了测试用例集执行的基本流程,TestRunner 是默认实现,并给出了用例计时功能。
TestSuite: 一个极简版组合模式的实现。
public class TestSuite implements Test {
private String fName;
private Vector<Test> fTests;
public void run(TestResult result) {
Iterator i$ = this.fTests.iterator();
while(i$.hasNext()) {
Test each = (Test)i$.next();
if (result.shouldStop()) {
break;
}
this.runTest(each, result);
}
}
}
public class Description implements Serializable {
private static final long serialVersionUID = 1L;
private static final Pattern METHOD_AND_CLASS_NAME_PATTERN = Pattern.compile("([\\s\\S]*)\\((.*)\\)");
public static final Description EMPTY = new Description((Class)null, "No Tests", new Annotation[0]);
public static final Description TEST_MECHANISM = new Description((Class)null, "Test mechanism", new Annotation[0]);
private final Collection<Description> fChildren;
private final String fDisplayName;
private final Serializable fUniqueId;
private final Annotation[] fAnnotations;
private volatile Class<?> fTestClass;
}
public class JUnitCore {
private final RunNotifier notifier = new RunNotifier();
Result runMain(JUnitSystem system, String... args) {
system.out().println("JUnit version " + Version.id());
JUnitCommandLineParseResult jUnitCommandLineParseResult = JUnitCommandLineParseResult.parse(args);
RunListener listener = new TextListener(system);
this.addListener(listener);
return this.run(jUnitCommandLineParseResult.createRequest(defaultComputer()));
}
public Result run(Runner runner) {
Result result = new Result();
RunListener listener = result.createListener();
this.notifier.addFirstListener(listener);
try {
this.notifier.fireTestRunStarted(runner.getDescription());
runner.run(this.notifier);
this.notifier.fireTestRunFinished(result);
} finally {
this.removeListener(listener);
}
return result;
}
}
RunNotifier 和 Description 的示例如下:
public abstract class ParentRunner<T> extends Runner implements Filterable, Sortable {
public void run(RunNotifier notifier) {
EachTestNotifier testNotifier = new EachTestNotifier(notifier, this.getDescription());
try {
Statement statement = this.classBlock(notifier);
statement.evaluate();
} catch (AssumptionViolatedException var4) {
testNotifier.addFailedAssumption(var4);
} catch (StoppedByUserException var5) {
throw var5;
} catch (Throwable var6) {
testNotifier.addFailure(var6);
}
}
protected Statement childrenInvoker(final RunNotifier notifier) {
return new Statement() {
public void evaluate() {
ParentRunner.this.runChildren(notifier);
}
};
}
}
即使极简如 JUnit4 , 也能学到很多:
本文探讨了最为简单的三个设计:Java 集合框架、Java IO 框架和 JUnit4 。这些简单的框架实现中,蕴含了很多经典的设计示例,能够帮助新手打下一个较好的代码设计基础。接下来,我们将会远航,去探索更加复杂的源码世界。
原文:https://www.cnblogs.com/lovesqcc/p/13336624.html