logo头像
ICQL

designpattern_结构型

结构型设计模式概述

主要总结了一些类或对象组合在一起的经典结构



代理模式

在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能,对客户端不透明

应用场景:

业务系统的非功能性需求开发:如打印日志,记录耗时,事务控制,幂等,限流,鉴权等等
rpc框架(远程请求包装成代理),缓存

实现:

代理类和被代理类实现同一个接口,代理类组合一个被代理类对象
代理类继承被代理类

分类:

静态代理:指手动编码每个被代理类的代理类
动态代理:利用jdk动态代理(实现同一接口)或 cglib(继承)实现的动态生成代理类

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
/**
* 继承实现的代理模式
*/
public class UserServiceProxy extends UserService {

@Override
public void action() {
//附加功能
System.out.println("代理类-action方法 执行了。。。");
super.action();
}
}

public class UserService {

public void action() {
System.out.println("被代理类-action方法 执行了。。。");
}
}


public interface UserService {
void action();
}

public class UserServiceImpl implements UserService {

@Override
public void action() {
System.out.println("被代理类-action方法 执行了。。。");
}
}

/**
* 基于接口实现的代理模式
*/
public class UserServiceProxy implements UserService {

private final UserServiceImpl userService = new UserServiceImpl();

@Override
public void action() {
//附加功能
System.out.println("代理类-action方法 执行了。。。");
userService.action();
}
}

/**
* 动态代理模式:基于接口实现-jdk动态代理
* 基于继承实现,cglib字节码技术可以动态代理
*/
public class UserServiceProxy {

private final UserServiceImpl userService = new UserServiceImpl();

public void action() {
UserService proxyService = (UserService) Proxy.newProxyInstance(
UserServiceProxy.class.getClassLoader(),
userService.getClass().getInterfaces(),
(proxy, method, args) -> {
//附加功能
Object obj = method.invoke(userService, args);
return obj;
});
proxyService.action();
System.out.println("代理类-action方法 执行了。。。");
}
}


桥接模式

不常用,将抽象部分与它的实现部分分离,使它们都可以独立地变化
一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展

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
public abstract class Shape {

protected Color color;

public Shape(Color color) {
this.color = color;
}

public abstract void printShape();
}

public class CircleShape extends Shape {

public CircleShape(Color color) {
super(color);
}

@Override
public void printShape() {
color.printColor();
System.out.println("圆形");
}
}

public class SquareShape extends Shape {

public SquareShape(Color color) {
super(color);
}

@Override
public void printShape() {
color.printColor();
System.out.println("正方形");
}
}

public interface Color {

void printColor();
}

public class RedColor implements Color {
@Override
public void printColor() {
System.out.println("红色");
}
}

public class WhiteColor implements Color {
@Override
public void printColor() {
System.out.println("白色");
}
}


装饰器模式

以对客户端透明的方式,动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活

应用例子:

购买煎饼,客户可自由选择加鸡蛋,加肉松,加火腿等等
java-io类中的经典实现

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
* 抽象的装饰器
*/
public abstract class Decorator implements Component {

private Component component;

public Decorator(Component component) {
this.component = component;
}

@Override
public void operation() {
component.operation();
}
}

/**
* 具体的装饰器1
*/
public class ConcreteDecorator1 extends Decorator {

public ConcreteDecorator1(Component component) {
super(component);
}

@Override
public void operation() {
super.operation();
addedOperation();
}

private void addedOperation() {
System.out.println("增加装饰器1");
}
}

/**
* 具体的装饰器2
*/
public class ConcreteDecorator2 extends Decorator {

public ConcreteDecorator2(Component component) {
super(component);
}

@Override
public void operation() {
super.operation();
addedOperation();
}

private void addedOperation() {
System.out.println("增加装饰器2");
}
}

/**
* 抽象构件
*/
public interface Component {

void operation();
}

/**
* 具体的构件1
*/
public class ConcreteComponent1 implements Component {

@Override
public void operation() {
System.out.println("具体的构件1");
}
}

/**
* 具体的构件2
*/
public class ConcreteComponent2 implements Component {

@Override
public void operation() {
System.out.println("具体的构件2");
}
}

public class DecoratorClient {

public static void main(String[] args) {
//java-io类库有同样的装饰器实现

Component component1 = new ConcreteComponent1();
ConcreteDecorator1 concreteDecorator1_1 = new ConcreteDecorator1(component1);
ConcreteDecorator2 concreteDecorator1_2 = new ConcreteDecorator2(concreteDecorator1_1);
concreteDecorator1_2.operation();

System.out.println();

Component component2 = new ConcreteComponent2();
ConcreteDecorator1 concreteDecorator2_1 = new ConcreteDecorator1(component2);
ConcreteDecorator2 concreteDecorator2_2 = new ConcreteDecorator2(concreteDecorator2_1);
concreteDecorator2_2.operation();
}
}


适配器模式

这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作

实现方式:

类适配器(继承)
对象适配器(组合)

应用场景:

适配接口,接口兼容,java-log的经典应用(slf4j)

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public interface ITarget {

void operationA();

void operationB();
}

/**
* 适配者1
*/
public class Adaptee1 {

public void operation1A() {
System.out.println("适配者1-操作A");
}

public void operation1B() {
System.out.println("适配者1-操作B");
}
}

/**
* 适配者2
*/
public class Adaptee2 {

public void operation2A() {
System.out.println("适配者2-操作A");
}

public void operation2B() {
System.out.println("适配者2-操作B");
}
}

/**
* 类适配器:缺陷,只能适配一个适配者
*/
public class ClazzAdaptor extends Adaptee1 implements ITarget {

@Override
public void operationA() {
//不需要修改,直接返回
super.operation1A();
}

@Override
public void operationB() {
//需要修改,重新实现
super.operation1B();
}
}

/**
* 对象适配器:可以综合适配多个适配者
*/
public class ObjectAdaptor implements ITarget {

private Adaptee1 adaptee1;

private Adaptee2 adaptee2;

public ObjectAdaptor(Adaptee1 adaptee1, Adaptee2 adaptee2) {
this.adaptee1 = adaptee1;
this.adaptee2 = adaptee2;
}

@Override
public void operationA() {
//不需要修改,直接返回
adaptee1.operation1A();
//adaptee2.operation2A();
}

@Override
public void operationB() {
//需要修改,重新实现
adaptee1.operation1B();
adaptee2.operation2B();
}
}

public class AdapterClient {

public static void main(String[] args) {
ITarget target1 = new ClazzAdaptor();
target1.operationA();
target1.operationB();

ITarget target2 = new ObjectAdaptor(new Adaptee1(), new Adaptee2());
target2.operationA();
target2.operationB();
}
}


门面模式

门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用
简而言之,就是聚合一些细粒度的接口或方法组装成一个面向用户用例的接口,提高易用性,解决一致性,以及一些性能问题



组合模式

不常用,将一组对象组织(Compose)成树形结构,以表示一种部分 - 整体的层次结构
应用场景,主要用于树形结构的数据



享元模式

  • 运用共享技术有效地支持大量细粒度对象的复用,最简单的办法就是用一个hashmap维护对象作为享元池
  • 享元对象能做到共享的关键是区分了内部状态和外部状态
  • 内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享
  • 外部状态是随环境改变而改变的、不可以共享的状态
  • 享元模式和对象池的区别:对象池中的对象在同一时间只能被一个线程使用,目的是为了节省时间,而享元模式则可以多个,目的是为了减少空间占用
  • java类库中的 Integer(IntegerCache) 和 String(字符串常量池) 的应用
微信打赏

赞赏是不耍流氓的鼓励