设计模式

refactoringgurusourcemaking

创建型模式

单例模式

  • 提前创建单例:适用于频繁使用,或者单例占用资源较少的情况。最简单创建单例的方式是使用枚举类。
  • 延迟创建单例:存在多线程问题,可以直接使用 synchronized 对整个方法进行同步。但实际上只有在第一次调用时才需要同步,所以更优的实现是使用双重检查加锁以及 volatile 关键字。
  • 当使用多个类加载器、反射和序列化/反序列化时,要注意避免创建多个单例实例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public final class Singleton {

private volatile static Singleton instance;
public String value;

private Singleton(String value) {
this.value = value;
}

public static Singleton getInstance(String value) {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(value);
}
}
}
return instance;
}
}

结构型模式

代理模式

Java 在 java.lang.reflect 包中有自己的代理支持,利用该包可以动态地创建代理类,所以该技术被称为动态代理

  • 实现 InvocationHandler 接口。
  • 以指定的对象和 InvocationHandler 实现类为参数,调用 Proxy.newProxyInstance 方法,创建代理对象。
  • 将代理对象强制类型转换为指定的对象所实现的某个接口类型,然后调用方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
interface Person {

void foo();
}

class PersonImpl implements Person {

@Override
public void foo() {
System.out.println(this.getClass().getName());
}
}

class MyInvocationHandler implements InvocationHandler {

private Person person;

public MyInvocationHandler(Person person) {
this.person = person;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 逻辑处理
System.out.println(this.getClass().getName());
return method.invoke(person, args);
}
}

class ProxyFactory {

public static Person getProxyInstance(Person person) {
return (Person) Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new MyInvocationHandler(person));
}
}

public class DynamicProxy {

public static Person getProxyInstance(Person person) {
return (Person) Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new MyInvocationHandler(person));
}

public static void main(String[] args) {
Person person = new PersonImpl();
Person proxyInstance = getProxyInstance(person);
proxyInstance.foo();
}
}

南京大学 操作系统 课程总结 2022

课程网站课程视频OSTEPCSAPP

Part 1

资料:The Feynman Lectures on PhysicsENIAC Simulator and Related Material

思考 Why - What - How,为什么 - 是什么 - 怎么做

Operating System: A body of software, in fact, that is responsible for making it easy to run programs (even allowing you to seemingly run many at the same time), allowing programs to share memory, enabling programs to interact with devices, and other fun stuff like that. (OSTEP)

关键问题:操作系统如何发展成现在这样的?(硬件、软件)


工具:gdbstrace。(tldrxxd

资料:Vim help fileslogisim.cseven-seg.pyminimal.S

以下代码是 logisim.c 的简化版,实现数字逻辑电路的模拟器。我们可以在 vim 中使用 !gcc % && ./a.out 命令,运行如下代码。代码中使用 X macro 技巧,我们可以使用 !gcc -E % 命令输出宏展开之后的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <unistd.h>

#define REGS_FOREACH(_) _(X) _(Y)
#define RUN_LOGIC X1 = !X && Y; \
Y1 = !X && !Y;
#define DEFINE(X) static int X, X##1;
#define UPDATE(X) X = X##1;
#define PRINT(X) printf(#X " = %d; ", X);

int main() {
REGS_FOREACH(DEFINE);
while (1) { // clock
RUN_LOGIC;
REGS_FOREACH(PRINT);
REGS_FOREACH(UPDATE);
putchar('\n'); sleep(1);
}
}
1
2
3
4
5
6
7
8
9
int main() {                                      
static int X, X1; static int Y, Y1;;
while (1) {
X1 = !X && Y; Y1 = !X && !Y;;
printf("X" " = %d; ", X); printf("Y" " = %d; ", Y);;
X = X1; Y = Y1;;
putchar('\n'); sleep(1);
}
}

程序 seven-seg.py 使用 ANSI escape code 来控制字符的颜色。\033[37m\033[31m 分别表示,将当前和之后的字符设置为白色、红色,而 \033[0m 表示重置设置。\033[2J 表示清空屏幕同时将光标移至左上角,\033[1;1f 表示将光标移至第 1 行和第 1 列(应该是这样,HVP 和 CUP 的区别没看懂)。最后,我们可以使用管道,将 logisim.c 的输出作为 seven-seg.py 的输入,从而模拟数码管的显示(执行 ./a.out | python3 seven-seg.py 命令)。

彩蛋:telnet towel.blinkenlights.nl(命令行电影),ssh sshtron.zachlatta.com(网络游戏)。(使用 ANSI escape code 实现)

关键概念:程序是状态机。可以从以下两个视角,抽象的理解。

  • 源代码视角:状态 = 栈帧列表(每个栈帧都有 PC)+ 全局变量。

  • 二进制视角:状态 = 寄存器 + 内存,程序 = 计算指令 + syscall 指令。

问题:如何构造一个最小的 “Hello, World” 程序?(RTFM,man syscall

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <sys/syscall.h>

.globl _start
_start:
movq $SYS_write, %rax // write(
movq $1, %rdi // fd=1,
movq $st, %rsi // buf=st,
movq $(ed - st), %rdx // count=ed-st
syscall // );

movq $SYS_exit, %rax // exit(
movq $1, %rdi // status=1
syscall // );

st:
.ascii "\033[01;31mHello, OS World\033[0m\n"
ed: