java设计模式

设计原则

单一职责原则

不要存在多于一个导致类变更的原因

接口隔离原则

客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上

依赖倒转原则

抽象不应该依赖于细节,细节应当依赖于抽象

里式替换原则

所有引用基类(父类)的地方必须能透明地使用其子类的对象

开闭原则

一个软件实体应当对扩展开放,对修改关闭

迪米特原则

一个软件实体应当尽可能少地与其他实体发生相互作用

合成复用原则

要尽量使用合成和聚合,尽量不要使用继承

类图六大关系

1
2
3
4
5
6
7
8
9
10
-- dependency(依赖关系)
用到了其他类,表现为局部变量
-- association(关联关系)
表现与全局变量
导航性多重性(一对一 一对多 多对一)
是依赖关系的特例
-- generalization(泛化关系)
-- implementation(实现关系)
-- aggregation(聚合关系) 整体和部分可以分开,是关联关系的特例
-- composite(组合关系)(合成) 整体和部分不可分割,是关联关系的特例

单例模式

单例类的职责过重,在一定程度上违背了“单一职责原则
不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态
单利模式中没有抽象层,因此单例类的扩展有很大的困难。

双重检验:第一次加载时反应不快,由于java内存模型一些原因偶尔失败
一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测

单例模式的经典使用场景:

  1. 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。

  2. 控制资源的情况下,方便资源之间的互相通信。如线程池等。

饿汉式

饿汉式(静态常量):在类加载的时候就完成实例化,没有达到懒加载的效果,如果自始至终没有用到这个实例,则会造成内存的浪费
饿汉单例模式一定要加final?
防止反射

必须加static,不能new

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleson {
private Singleson() {

}

//加final防止反射
private final static Singleson INSTANCE = new Singleson();


public static Singleson getInstance() {
return INSTANCE;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleson {
private Singleson() {

}

private final static Singleson INSTANCE ;

static {
INSTANCE = new Singleson();
}

public static Singleson getInstance() {
return INSTANCE;
}
}
懒汉式

//final关键字:其初始化可以在两个地方,一是其定义处,也就是说在final变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值

(线程不安全)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Singleson {
private Singleson() {

}
private static Singleson INSTANCE;


public static Singleson getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleson();
}
return INSTANCE;
}
}

(线程安全效率低)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Singleson {
private Singleson() {

}

private static Singleson INSTANCE;

public static synchronized Singleson getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleson();
}
return INSTANCE;
}
}

(错误的写法,多线程时,另一个线程已经进入了if-null的判断了,一个线程执行完,另一个线程也要再一次地创建对象把锁加载if那同加载方法那效果一直)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Singleson {
private Singleson() {

}

private static Singleson INSTANCE;

public static Singleson getInstance() {
if (INSTANCE == null) {
synchronized (Singleson.class) {
INSTANCE = new Singleson();
}
}
return INSTANCE;
}
}
双重检验

(懒加载)

(volatile关键字的作用防止指令重排)
(解释双重检验:多线程的情形下,两个线程都进入到第一个if判断中了,一个线程进入到锁中,然后创建完对象,释放锁,另一个线程进入到第二个判断,但是已经new了一个对象了,所以不为null 直接出去,对于性能,因为对象已经存在所以第一个判断if都不会进入,并不会影响性能)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Singleson {
private Singleson() {

}

private static volatile Singleson INSTANCE;

public static Singleson getInstance() {
if (INSTANCE == null) {
synchronized (Singleson.class) {
if (INSTANCE == null) {
INSTANCE = new Singleson();
}
}
}
return INSTANCE;
}
}
静态内部类

特性:内部静态类不会自动初始化,只有调用静态内部类的方法,静态域,或者构造方法的时候才会加载静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleson {
private Singleson() {

}

private static class SinglesonInstance {
private static Singleson INSTANCE = new Singleson();
}

public static Singleson getInstance() {
return SinglesonInstance.INSTANCE;
}
}
枚举
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test3 {
public static void main(String[] args) {
Singleson instance = Singleson.INSTANCE;
Singleson instance1 = Singleson.INSTANCE;
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
instance.show();
}
}

enum Singleson {
INSTANCE;
public void show(){
System.out.println("ok");
}

}

工厂模式

简单工厂模式
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
public class Client {
public static void main(String[] args) throws Exception {
Product a = Factory.newProduct("A");
Product b = Factory.newProduct("B");
try {
a.show();
b.show();
} catch (Exception e) {
e.printStackTrace();
}

}
}

interface Product {
void show();
}

class ProductA implements Product {

@Override
public void show() {
System.out.println("A产品");
}
}

class ProductB implements Product {

@Override
public void show() {
System.out.println("B产品");
}
}

class Factory {

static Product newProduct(String product) throws Exception {

switch (product) {
case "A":
return new ProductA();

case "B":
return new ProductB();

default:
break;
}
throw new Exception("没有该产品");
}
}

工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产

品,简单工厂模式实现了对象创建和使用的分离。

会导致系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和

维护,且违背开闭原则

适用的场合:工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂

工厂方法模式
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
public class Client {
public static void main(String[] args) {
Factory jFactory = new JFactory();
jFactory.operation();
Factory xFactory = new XFactory();
xFactory.operation();

}
}

interface Factory{
void operation();
}

class JFactory implements Factory{
@Override
public void operation() {
System.out.println("-");
}
}
class XFactory implements Factory{
@Override
public void operation() {
System.out.println("*");
}
}
class CFactory implements Factory{
@Override
public void operation() {
System.out.println("/");
}
}

定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类

工厂一旦需要生产新产品就需要修改工厂类的方法逻辑,违背了“开放 - 关闭原则,工厂方法新增一种产品时,只需要增加相应的具体产品

类和相应的工厂子类即可,

工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了

多态性的体现

每次我们为工厂方法添加新的产品时就要编写一个新的产品类,同时还要引入抽象层,当产品种类非常多时,会出现大量的与之对应的工

厂对象,这必然会导致类结构的复杂化

抽象工厂模式
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
106
107
108
109
110
111
112
113
114
public class Client {
public static void main(String[] args) {
//测试
XMProductFactory xmProductFactory = new XMProductFactory();
xmProductFactory.phoneProduct().open();
xmProductFactory.routerProduct().open();
PGProductFactory pgProductFactory = new PGProductFactory();
pgProductFactory.phoneProduct().open();
pgProductFactory.routerProduct().open();
//如果往产品中添加功能要修改代码复杂,如果要,如果要添加产品则要修改工厂方法复杂不适用
}
}

//产品接口
interface PhoneProduct {
void open();

void close();
}

interface PouterProduct {
void open();

void close();
}

//小米和苹果实现类
class XMPhoneProduct implements PhoneProduct {

@Override
public void open() {
System.out.println("打开小米手机");
}

@Override
public void close() {
System.out.println("关闭小米手机");
}
}

class PGPhoneProduct implements PhoneProduct {

@Override
public void open() {
System.out.println("打开苹果手机");
}

@Override
public void close() {
System.out.println("关闭苹果手机");
}
}

class XMPouterProduct implements PouterProduct {

@Override
public void open() {
System.out.println("打开小米路由器");
}

@Override
public void close() {
System.out.println("关闭小米路由器");
}
}

class PGPouterProduct implements PouterProduct {

@Override
public void open() {
System.out.println("打开苹果路由器");
}

@Override
public void close() {
System.out.println("打开苹果路由器");
}
}

//抽象工厂
interface ProductFactory {
//生产手机
PhoneProduct phoneProduct();

//生成路由器
PouterProduct routerProduct();
}

//小米工厂和苹果工厂
class XMProductFactory implements ProductFactory {

@Override
public PhoneProduct phoneProduct() {
return new XMPhoneProduct();
}

@Override
public PouterProduct routerProduct() {
return new XMPouterProduct();
}
}

class PGProductFactory implements ProductFactory {

@Override
public PhoneProduct phoneProduct() {
return new PGPhoneProduct();
}

@Override
public PouterProduct routerProduct() {
return new PGPouterProduct();
}
}

抽象工厂模式是所有工厂模式的一般形式,当抽象工厂模式退化到只有一个产品登级结构时,就变成了工厂方法模式。当工厂方法模式的工

厂类只有一个时,且工厂方法为静态方法时,则又变成了简单工厂模式。与工厂方法模式相似,抽象工厂模式隔离了具体类的生成,让客户端不

清楚具体什么样的对象被创建

但是产品族扩展非常困难,要增加一个系列的某一产品,既要修改工厂抽象类里加代码,又修改具体的实现类里面加代码

增加了系统的抽象性和理解难度

原型模式

浅拷贝和深拷贝