适配器模式

"adapter"

将一个类的接口转换成另一个接口。 Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

目标接口Target

1
2
3
public interface Target {
void operation1();
}

待适配类Adaptee,与目标接口不一致

1
2
3
public class Adaptee {
void operation2() {}
}

适配器类

1
2
3
4
5
6
7
8
public class Adapter implements Target {
private Adaptee adaptee = new Adaptee();

public void operation1() {
// do something
adaptee.sampleOperation1();
}
}

测试类

1
2
3
4
5
6
7
8
9
10
public class AdapterClient {
public static void main(String... args) {
Target adapter = new Adapter();
adapter.operation1();

// 比如目标接口的一个实现是Concrete,客户端感知不到接口的不同
// Target concrete = new Concrete();
// concrete.operation1
}
}

单例模式

懒汉式——线程不安全

1
2
3
4
5
6
7
8
9
10
public class Singleton0 {
private static Singleton0 singleton0;
private Singleton0() {}
public static Singleton0 getInstance() {
if (singleton0 == null) {
singleton0 = new Singleton0();
}
return singleton0;
}
}

懒汉式——线程安全,但浪费内存

1
2
3
4
5
6
7
8
9
10
public class Singleton1 {
private static Singleton1 singleton1;
private Singleton1() {}
public static synchronized Singleton1 getInstance() {
if (singleton1 == null) {
singleton1 = new Singleton1();
}
return singleton1;
}
}

饿汉式——线程安全,但浪费内存

1
2
3
4
5
6
7
public class Singleton2 {
private static Singleton2 singleton2 = new Singleton2();
private Singleton2() {}
public static Singleton2 getInstance() {
return singleton2;
}
}

登记式/静态内部类——推荐

1
2
3
4
5
6
7
8
9
public class Singleton3 {
private static class SingletonHolder {
private static Singleton3 singleton3 = new Singleton3();
}
private Singleton3() {}
public static Singleton3 getInstance() {
return SingletonHolder.singleton3;
}
}

双检锁(DCL)——推荐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton4 {
// volatile禁止指令重排序
private volatile static Singleton4 singleton4;
private Singleton4() {}
public static Singleton4 getInstance() {
if (singleton4 == null) {
synchronized (Singleton4.class) {
if (singleton4 == null) {
singleton4 = new Singleton4();
}
}
}
return singleton4;
}
}

枚举——推荐

1
2
3
4
5
6
7
8
public enum Singleton5 {
INSTANCE;
public void whatSoEverMethod() { }
// 该方法非必须
public static Singleton5 getInstance() {
return INSTANCE;
}
}

建造者模式

"builder"

建造者模式与抽象工厂方式都是用来创建复杂的大对象,但builder模式是一步步创建,一般不是直接返回对象。好处是对象的构建代码与标识代码分离了。

要建造的产品

1
2
3
4
public class Product {
private String part1;
private String part2;
}

建造者接口

1
2
3
4
5
public interface Builder {
void buildPart1();
void buildPart2();
Product getProduct();
}

具体的建造者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ConcreteBuilder implements Builder {
private Product product = new Product();

public void buildPart1() {
product.setPart1("NO: 89757");
}

public void buildPart2() {
product.setPart2("NAME: abc");
}

public Product getProduct() {
return product;
}
}

Director类

1
2
3
4
5
6
7
8
9
10
11
12
public class Director {
private Builder builder;

public Director(Builder builder) {
this.builder = builder;
}

public void construct() {
builder.buildPart1();
builder.buildPart2();
}
}

具体使用的测试类

1
2
3
4
5
6
7
8
9
public class Client {
public static void main(String... args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getProduct();
System.out.print(product);
}
}

原型模式

"prototype"

原型模式通过复制原型(prototype)获得创建新对象的能力,原型本身就是个工厂。用于隔离类的使用者和具体类型之间的耦合关系,隐藏了对象创建的细节,避免了调用过多参数的构造方法而带来的性能影响。与抽象工厂方法的却别在于重在自身的复制。

原型接口,自行实现clone,也可以是实现Cloneable的抽象类

1
2
3
public interface Prototype {
Object clone();
}

具体对象

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ConcretePrototypeA implements Prototype {
@Override
public Object clone() {
return new ConcretePrototypeA();
}
}

public class ConcretePrototypeB implements Prototype {
@Override
public Object clone() {
return new ConcretePrototypeB();
}
}

测试类

1
2
3
4
5
6
7
8
9
public class Test {
public static void main(String... args) {
Prototype
prototype1 = new ConcretePrototypeA(),
prototype2 = new ConcretePrototypeB();
ConcretePrototypeA concretePrototypeA = (ConcretePrototypeA) prototype1.clone();
ConcretePrototypeB concretePrototypeB = (ConcretePrototypeB) prototype2.clone();
}
}

抽象工厂模式

"abstract-factory"

核心思想:向客户端提供一个接口,使得客户端在不必指定具体产品的情况下,创建多个产品族中的产品对象

与工厂方法模式的区别:工厂方法模式中一种工厂只能创建一种具体产品。而在抽象工厂模式中一种具体工厂可以创建多个种类的具体产品

抽象产品(CPU、主板)

1
2
3
4
5
6
7
public interface Cpu {
public void calculate();
}

public interface MainBoard {
public void installCPU();
}

具体CPU产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// AMD CPU
public class AmdCpu implements Cpu {
private int pins = 0;
public AmdCpu(int pins) {
this.pins = pins;
}
@Override
public void calculate() {
System.out.println("AMD CPU 的针脚数" + pins);
}
}

// INTEL CPU
public class IntelCpu implements Cpu {
private int pins = 0;
public IntelCpu(int pins) {
this.pins = pins;
}
@Override
public void calculate() {
System.out.println("Intel CPU 的针脚数" + pins);
}
}

具体主板产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// AMD主板
public class AmdMainBoard implements MainBoard {
private int cpuHoles = 0;
public AmdMainBoard(int cpuHoles) {
this.cpuHoles = cpuHoles;
}
@Override
public void installCPU() {
System.out.println("AMD主板的CPU插槽孔数是:" + cpuHoles);
}
}

// INTEL主板
public class IntelMainBoard implements MainBoard {
private int cpuHoles = 0;
public IntelMainBoard(int cpuHoles) {
this.cpuHoles = cpuHoles;
}
@Override
public void installCPU() {
System.out.println("Intel主板的CPU插槽孔数:" + cpuHoles);
}
}

抽象工厂类

1
2
3
4
public interface AbstractFactory {
public Cpu createCpu();
public MainBoard createMainBoard();
}

具体工厂类

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
// AMD工厂
public class AmdFactory implements AbstractFactory {
@Override
public Cpu createCpu() {
return new AmdCpu(938);
}

@Override
public MainBoard createMainBoard() {
return new AmdMainBoard(938);
}
}

// INTEL工厂
public class IntelFactory implements AbstractFactory {
@Override
public Cpu createCpu() {
return new IntelCpu(755);
}

@Override
public MainBoard createMainBoard() {
return new IntelMainBoard(755);
}
}

测试类

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
public class ComputerEngineer {
private Cpu cpu = null;
private MainBoard mainboard = null;

public static void main(String... args) {
AbstractFactory
amdFactory = new AmdFactory(),
intelFactory = new IntelFactory();
ComputerEngineer engineer = new ComputerEngineer();
engineer.makeComputer(amdFactory);
engineer.makeComputer(intelFactory);
}

public void makeComputer(AbstractFactory af) {
/**
* 组装机器的基本步骤
*/
//1:首先准备好装机所需要的配件
prepareHardwares(af);
//2:组装机器
//3:测试机器
//4:交付客户
}

private void prepareHardwares(AbstractFactory af){
//这里要去准备CPU和主板的具体实现,为了示例简单,这里只准备这两个
//可是,装机工程师并不知道如何去创建,怎么办呢?

//直接找相应的工厂获取
this.cpu = af.createCpu();
this.mainboard = af.createMainBoard();

//测试配件是否好用
this.cpu.calculate();
this.mainboard.installCPU();
}
}

工厂方法模式

"factory-method"

工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 抽象工厂类
abstract class Factory {
public abstract Product produce();
}

// 具体工厂A——生产A
class Factory AF extends Factory {
@Override
public Product produce() {
return new A();
}
}

// 具体工厂B——生产B
class Factory BF extends Factory {
@Override
public Product produce() {
return new B();
}
}

产品类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 抽象产品类
abstract class Product {
public abstract void show();
}

// 具体产品类A
class Product A extends Product {
@Override
public void show() {
System.out.println("product A");
}
}

// 具体产品类B
class Product B extends Product {
@Override
public void show() {
System.out.println("product B");
}
}

测试类

1
2
3
4
5
6
7
public class Test {
public static void main(String... args) {
Factory af = new AF();
Product a = af.produce();
a.show();
}
}

简单工厂模式与OOP原则

已遵循的原则
  • 依赖倒置原则
  • 迪米特法则
  • 里氏替换原则
  • 接口隔离原则
  • 单一职责原则(每个工厂只负责创建自己的具体产品,没有简单工厂中的逻辑判断)
  • 开闭原则(增加新的产品,不像简单工厂那样需要修改已有的工厂,而只需增加相应的具体工厂类)
未遵循的原则
  • 开闭原则(虽然工厂对修改关闭了,但更换产品时,客户代码还是需要修改)

简单工厂模式

"simple-factory"

1
2
3
abstract class Car {
public abstract void speed();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class BMW extends Car {
@Override
public void speed() {
// do something
}
}

public class Benz extends Car {
@Override
public void speed() {
// do something
}
}
1
2
3
4
5
6
7
8
9
10
11
12
class Factory {
public static Car produce(String productName) {
switch(productName) {
case "BMW":
return new BMW();
case "Benz":
return new Benz();
default:
return null;
}
}
}
1
2
3
4
5
6
7
8
9
public class Driver {
public void drive() {
// 可以根据配置文件来读取产品名称
XMLConfiguration config = new XMLConfiguration("car.xml");
String productName = config.getString("BMW");
Car car = Factory.produce(productName);
car.speed();
}
}

简单工厂模式与OOP原则

已遵守的原则
  • 依赖倒置原则
  • 迪米特法则
  • 里氏替换原则
  • 接口隔离原则
未遵循的原则
  • 开闭原则(如上文所述,利用配置文件+反射或者注解可以避免这一点)
  • 单一职责原则(工厂类即要负责逻辑判断又要负责实例创建)

六大原则:

  • SRP(Single Responsibility Principle)——单一职责。只有一个原因引起变化
  • LSP(Substitution Principle)——里氏替换。所有引用基类的地方必须能透明地使用子类对象
    • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
    • 子类中可以增加自己特有的方法
    • 子类重载父类方法时,入参要比父类入参更宽
    • 子类实现父类方法时,返回值要比父类更严格
  • DIP(Dependency Inversion Principle)——依赖倒置。依赖抽象而不是细节,面向接口编程,模块之间解耦
  • ISP(Interface Segregation Principle)——接口隔离。客户端不应该依赖它不需要的接口
  • LOD(Law Of Demeter)——迪米特法则。对象之间耦合少。但是这种解耦是有限度的,否则会产生大量的跳转类。若一个类通过跳转两次以上去访问另一个类,则就要重构了。注意,需要适度考虑这个原则。
  • OCP(Open Closed Principle)——开闭原则。对扩展开放,对修改关闭,其实是一个核心思想,前5个原则遵守的好,开闭原则自然就遵守的好了。

按照使用场景,设计模式分为三大类:

  • 创建型(Creation Patterns)
    • 工厂模式
    • 原型模式
    • 构建者模式
    • 单例模式
  • 结构型(Structural Patterns)
    • 适配器模式
    • 桥接模式
    • 过滤器模式
    • 组合模式
    • 装饰者模式
    • 门面模式
    • 享元模式
    • 代理模式
  • 行为型(Behavioral Patterns)
    • 责任链模式
    • 命令模式
    • 解释器模式
    • 迭代器模式
    • 中介者模式
    • 备忘录模式
    • 观察者模式
    • 状态模式
    • 空对象模式
    • 策略模式
    • 模板模式
    • 访问者模式

UML类图常用关系:

  • 泛化(Generalization)
    • 继承关系,表示一般与特殊
    • 带三角箭头的实线,箭头指向父类
  • 实现(Realization)
    • 类与接口的关系,表示类是接口所有特征和行为的实现
    • 带三角箭头的虚线,箭头指向接口
  • 关联(Association)
    • 拥有关系,表示一个类知道另一个类的属性和方法
    • 带普通箭头的实线,箭头指向被拥有者
  • 聚合(Aggregation)
    • 整体与部分的关系,且部分可以离开整体单独存在
    • 带空心菱形的实线,菱形指向整体
  • 组合(Composition)
    • 整体与部分的关系,但部分不能离开整体单独存在
    • 带实心菱形的实线,菱形指向整体
  • 依赖(Dependency)
    • 使用的关系,表示一个类需要另一个类的协助
    • 带箭头的虚线,箭头指向被使用者

"uml"

Callable提供了带返回值的子线程执行结果,Future提供了获取子线程结果的途径

1
2
3
4
Callable<String> callable = () -> null;
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(callable);
System.out.println(future.get());

但是,这种直接get()的方式是同步阻塞的,当然,如果轮询isDone()的话仍然是换汤不换药。关于老生常谈的同步、异步、阻塞、非阻塞,这篇《I/O模型》从Java的视角出发来讲解,特别是NIOAIO,指出AIO并不是字面上的异步含义,值得一看。
那么对于Future模式,除了上文的将来式get()这种不优雅的同步阻塞方案,还有没有其他的方式可以拿到子线程结果呢?
很容易想到的一种方式是使用回调。如AIO提供了java.nio.channels.CompletionHandler作为回调接口,当I/O操作结束后,系统将会调用CompletionHandlercompletedfailed方法来结束一次调用

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
/* Server */
AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup
.withThreadPool(executor);
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel
.open(channelGroup)
.bind(new InetSocketAddress(serverPort));
serverChannel.accept(
null,
new CompletionHandler<AsynchronousSocketChannel, Object>() {
@Override
public void completed(AsynchronousSocketChannel result, Object attach) {
// doSomething()
serverChannel.accept(null, this);
}

@Override
public void failed(Throwable exc, Object attach) { }
});

/* Client */
AsynchronousSocketChannel clientChannel = AsynchronousSocketChannel.open();
clientChannel.connect(new InetSocketAddress(clientPort));
clientChannel.read(
ByteBuffer.allocate(1024),
null,
new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {
// doSomething()
}

@Override
public void failed(Throwable exc, Object attachment) { }
});

JDK5NIO已经提供了相关的API,虽然操作更为复杂一些,但在此基础上,诸如Netty等通信框架已经发展的十分繁荣。AIO似乎并没有达到预计的效果,但这种回调方式显然要比直接get()的粗暴方式要更为优雅。
那么有没有不那么粗暴又方便一些的回调方案呢?
答案是有的,一些开源的工具已经为我们提供了这个功能,例如接下来要介绍的Google扩展包Guava中提供的并发工具com.google.common.util.concurrent.ListenableFuture

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
public static void main(String... args) {
// 对jdk提供的线程池进行修饰,用于返回ListenabledFuture
ListeningExecutorService executorService = MoreExecutors
.listeningDecorator(Executors.newCachedThreadPool());

// 提交一个Callable,返回ListenableFuture
final ListenableFuture<Integer> listenableFuture = executorService.submit(() -> {
System.out.println("call execute..");
TimeUnit.SECONDS.sleep(1);
return 7;
});

// 为listenableFuture添加回调函数,没有任何异常则分支进入onSuccess处理,否则进入onFailure分支
Futures.addCallback(listenableFuture, new FutureCallback() {
public void onSuccess(Object o) {
System.out.println("异步处理成功,result="+o);
}

public void onFailure(Throwable throwable) {
System.out.println("异步处理失败,e="+throwable);
}
}, MoreExecutors.directExecutor());

System.out.println("不会阻塞");

}

Futureget()会阻塞主线程不同,带监听器的ListenableFuture可以异步处理Callable结果,最终打印结果:

1
2
3
call execute..
不会阻塞
异步处理成功,result=7

ListeningExecutorService这个修饰后的线程池出发,看看如何修饰后如何将提交的Callable输出为ListenableFuture,而非Future,主要来看submit方法。
"AbstractListeningExecutorService"

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
public abstract class AbstractListeningExecutorService extends AbstractExecutorService
implements ListeningExecutorService {
@Override
public <T> ListenableFuture<T> submit(Callable<T> task) {
return (ListenableFuture<T>) super.submit(task);
}

@Override
protected final <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return TrustedListenableFutureTask.create(callable);
}
}

public abstract class AbstractExecutorService implements ExecutorService {
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
}

这里的submitnewTaskFor最终执行的都是子类AbstractListeningExecutorService中的,这是Guava包内的,而非J.C.U包内的AbstractExecutorService,返回了TrustedListenableFutureTask的实例,看一下依赖关系,能很清楚地看到这是ListenableFuture的一个实现类。
"AbstractListeningExecutorService"
那么是如何进行回调的呢?接着从刚才的实现类TrustedListenableFutureTask来看,主要做的工作是InterruptibleTask里,实现了Runnablerun方法。

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class TrustedListenableFutureTask<V> extends FluentFuture.TrustedFuture<V>
implements RunnableFuture<V> {

private volatile InterruptibleTask<?> task;

TrustedListenableFutureTask(Callable<V> callable) {
this.task = new TrustedFutureInterruptibleTask(callable);
}
}

abstract class InterruptibleTask<T> extends AtomicReference<Runnable> implements Runnable {
// DoNothingRunnable什么也不做,空转
private static final Runnable DONE = new DoNothingRunnable(); // 完成中断,置为DONE
private static final Runnable INTERRUPTING = new DoNothingRunnable();
private static final Runnable PARKED = new DoNothingRunnable();
// Why 1000? WHY NOT! 【😐】
private static final int MAX_BUSY_WAIT_SPINS = 1000;
@Override
public final void run() {
Thread currentThread = Thread.currentThread();
if (!compareAndSet(null, currentThread)) {
return; // 已经有其他运行的线程,CAS失败
}
boolean run = !isDone();
T result = null;
Throwable error = null;
try {
if (run) {
result = runInterruptibly(); // 最终执行了callable.call()
}
} catch (Throwable t) {
error = t;
} finally {
// 尝试将当前线程置为DONE
if (!compareAndSet(currentThread, DONE)) {
boolean restoreInterruptedBit = false;
int spinCount = 0;
Runnable state = get();
while (state == INTERRUPTING || state == PARKED) {
spinCount++;
// 超过最大自旋次数
if (spinCount > MAX_BUSY_WAIT_SPINS) {
if (state == PARKED || compareAndSet(INTERRUPTING, PARKED)) {
// 恢复中断标志位
restoreInterruptedBit = Thread.interrupted()||restoreInterruptedBit;
LockSupport.park(this); // 阻塞线程
}
} else {
Thread.yield(); // 自旋让步
}
state = get(); // 更新状态
}
if (restoreInterruptedBit) {
currentThread.interrupt(); // 有中断
}
}
// 完成中断
if (run) {
afterRanInterruptibly(result, error);
}
}
}

// 在runInterruptibly之前调用,如果是true,runInterruptibly和afterRanInterruptibly不再调用
abstract boolean isDone();

// 不计算Futures的结果,只处理可中断任务,因为listener有可能被中断
abstract T runInterruptibly() throws Exception;

// 计算Futures的结果,任何调用interruptTask发生的中断,都在此方法被调用前发生
abstract void afterRanInterruptibly(@Nullable T result, @Nullable Throwable error);
}