Design-Patterns-3

Design Patterns 创建型模式

Prototype Pattern

The Problem

Solution

Implementation

Exercise

Singleton Pattern

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

The Problem

我们看到,如果不是用单例模式创建的类,可以申明多个实例,每个实例之间是互相独立的。那么有没有办法,能让这个类只能有唯一实例,而且提供给其他对象这个唯一实例呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ConfigManager {
private Map<String,Object> settings = new HashMap<String,Object>();

public void set(String key,Object value) {
settings.put(key,value);
}

public Object get(String key) {
return settings.get(key);
}
}

public class Main {
public static void main(String[] args) {
ConfigManager manager = new ConfigManager();//创建了ConfigManager第一个实例
manager.set("name","Mosh");//设置一个键值对
ConfigManager other = new ConfigManager();//创建了第二个实例,但是查询结果为null
System.out.println(other.get("name")); //null
}
}

此外还有如下应用场景:

  • 一个班级只有一个班主任。
  • Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
  • 一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
  • 要求生产唯一序列号。
  • WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
  • 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

Solution

如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:构造函数是私有的。

我们将创建一个 SingleObject 类。SingleObject 类有它的私有构造函数和本身的一个静态实例。

SingleObject 类提供了一个静态方法,供外界获取它的静态实例SingletonPatternDemo 类使用 SingleObject类来获取 SingleObject对象。

Implementation

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 class ConfigManager {
private Map<String,Object> settings = new HashMap<String,Object>();
//必须设为静态的
private static ConfigManager instance = new ConfigManager();//实例在类中构造
//必须设为静态的,只能类内调用
public static ConfigManager getInstance() {//单例getter
return instance;
}

private ConfigManager() {} //私有的构造函数
public void set(String key,Object value) {
settings.put(key,value);
}
public Object get(String key) {
return settings.get(key);
}
}

public class Main {
public static void main(String[] args) {
ConfigManager manager = ConfigManager.getInstance();
manager.set("name","Jason");
ConfigManager other = ConfigManager.getInstance();//类外获得的始终是一个实例
System.out.println(other.get("name")); //Jason
}
}

小结

优点:

  • 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
  • 2、避免对资源的多重占用(比如写文件操作)。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

Exercise

Look at the Logger class in the singleton package of the Exercises project. With the current implementation, we can create multiple loggers writing to the same log file in parallel.

Use the singleton pattern to ensure only a single logger can be instantiated for a given file.

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
public class MyLogger {
private static List<String> loggerList = new ArrayList<String>();
private static MyLogger instance = new MyLogger();
public static MyLogger getInstance() {
return instance;
}
private MyLogger(){};

public List<String> getLoggerList() {
return loggerList;
}

public static void printLog(){
for(String log : loggerList){
System.out.println(log);
}
}
public void addLog(String log) {
loggerList.add(log);
}
}

public class Main {
public static void main(String[] args) {
MyLogger logger = MyLogger.getInstance();

logger.addLog("2022 8 22 11:26");

MyLogger logger2 = MyLogger.getInstance();
logger2.addLog("2022 8 22 11:27");

MyLogger.printLog();
//2022 8 22 11:26
//2022 8 22 11:27
}
}

Factory Method Pattern

The Problem

Solution

Implementation

Exercise

Abstract Factory Pattern

The Problem

Solution

Implementation

Exercise

Builder Pattern

The Problem

Solution

Implementation

Exercise

-------------本文结束,感谢您的阅读-------------