工作用用到的设计模式

聊到设计模式的时候,总是不知从何说起,记录一下JDK和工作中用到的部分设计模式,方便组织语言。JDK哪个地方用到了哪种设计模式,模式的一句话定义(最好背下专业术语),工作中是否也用到了,怎么用。

JDK中的设计模式

记忆可以从List开始,List遍历用到了Iterator,就是迭代器模式,迭代器模式是提供一种方法顺序访问一个聚合对象中各个元素吗,而又不暴露该对象的内部展示。

java.util.Iterator
java.util.Enumeration

List中 addAll可以把一个list加入到另一个list,即组合模式。组合模式又叫做部分-整体模式,使得客户端看来单个对象和对象的组合是同等的。换句话说,某个类型的方法同时也接受自身类型作为参数。类似的Map、Set 的putAll、addAll都是组合模式。

java.util.Map#putAll(Map)
java.util.List#addAll(Collection)
java.util.Set#addAll(Collection)

List 要排序,可以用java.util.Collections#sort()模板方法模式让子类可以重写方法的一部分,而不是整个重写,你可以控制子类需要重写那些操作。使用模板方法的还有

java.util.Collections#sort()
java.io.InputStream#skip()
java.io.InputStream#read()
java.util.AbstractList#indexOf()

接下来,是享元模式,运用共享技术有效地支持大量细粒度的对象。因为这个涉及到缓存池,可以一起记忆。

java.lang.Integer#valueOf(int) -128 and 127
java.lang.Boolean#valueOf(boolean) 布尔类型中的两个取值
java.lang.Byte#valueOf(byte) byte类型所有数据,即-128~127
java.lang.Character#valueOf(char) char类型所有数据,即所有字符 \u0000 to \u007F

比如,Integer的valueOf(int i),在i的范围在IntegerCache.low和IntegerCache.high之间是直接从缓存数组中取。范围是-127~128

1
2
3
4
5
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

StringBuilder#append()中的建造者模式,定义了一个新的类来构建另一个类的实例,以简化复杂对象的创建。建造模式通常也使用方法链接来实现。

工厂模式,分为简单工厂模式、工厂方法模式、抽象工厂模式。

它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象

简单工厂:把对象的创建放到一个工厂类中,通过参数来创建不同的对象。

工厂方法:每种产品由一种工厂来创建。java.lang.Object#toString(),提供一个工厂方法,创建对象由子类实现。

抽象工厂:感觉只是工厂方法的复杂化,产品系列复杂化的工厂方法。java.util.Arrays#asList()

一个创建新对象的方法,返回的却是接口或者抽象类的,就是抽象工厂模式了

最后一个是单例模式,单例模式的实现可以拉开来讲很多。

JDK中,java.lang.Runtime用到了饿汉式单例模式。

1
2
3
4
5
6
7
8
9
public class Runtime {
private static Runtime currentRuntime = new Runtime();

public static Runtime getRuntime() {
return currentRuntime;
}

private Runtime() {}
}

Spring的bean默认也是单例的。

可能大部分时候都不会碰到问你了解的JDK中的设计模式,JDK中用到的设计模式也非常多,关键能不能把主动权掌握在自己手里。把自己知道的说出来。

工作中用到了设计模式

工作中用到的设计模式也准备几种,根据具体业务来说。

策略模式

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法

业务场景: 系统中有一类消息,需要推送到一个kafka,一个mq,消息格式是不一样的。那么可以定义一个接口 MessageStrategy ,里面定义发送消息的方法,

1
2
3
public interface MessageStrategy {
void sendMessage(Object message);
}

再写两个类实现KafkaMessageStrategy 和 MqMessageStrategy 实现MessageStrategy ,

1
2
3
4
5
6
7
public class KafkaMessageStrategy implements MessageStrategy {
@Override
public void sendMessage(Object message) {
// 消息处理 省略
System.out.println("send kafka message");
}
}
1
2
3
4
5
6
7
public class MqMessageStrategy implements MessageStrategy {
@Override
public void sendMessage(Object message) {
// 消息处理 省略
System.out.println("send mq message");
}
}

一个context用于使用策略。

1
2
3
4
5
6
7
8
9
10
11
public class MessageContext {
private MessageStrategy messageStrategy;

public MessageContext(MessageStrategy messageStrategy) {
this.messageStrategy = messageStrategy;
}

public void executeMessage(Object message) {
messageStrategy.sendMessage(message);
}
}

使用方式

1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args) {
String message = "a message";
MessageContext messageContext = new MessageContext(new KafkaMessageStrategy());
messageContext.executeMessage(message);

messageContext = new MessageContext(new MqMessageStrategy());
messageContext.executeMessage(message);
}
}

模板模式

在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式

业务场景:系统中有人员出入小区时间记录,对人员行为进行模型分析计算,取出人员是可能需要作一些去重、过滤等操作, 之后根据模型规则进行分析,模型有多种,如早出晚归、昼伏夜出,那么可以将模型分析之前的操作写到抽象类的公共方法中,具体模型分析则调用对应的子类。

定义一个抽象类作为模板

1
2
3
4
5
6
7
8
9
10
11
public abstract class ModelTemplate {
// 模板
public final void modelAnalysis(){
initData();
analysisData();
}

abstract void initData();
abstract void analysisData();

}

两个模型

1
2
3
4
5
6
7
8
9
10
11
public class AModel extends ModelTemplate {
@Override
void initData() {
System.out.println("init data A");
}

@Override
void analysisData() {
System.out.println("analysis data A");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class BModel extends ModelTemplate {

@Override
void initData() {
System.out.println("init data B");
}

@Override
void analysisData() {
System.out.println("analysis data B");
}
}

使用

1
2
3
4
5
6
7
8
9
public class Test {
public static void main(String[] args) {
ModelTemplate model = new AModel();
model.modelAnalysis();

model = new BModel();
model.modelAnalysis();
}
}