⭐工厂模式(Factory)
对象的创建逻辑比较复杂,就可以考虑使用工厂模式,把对象的创建过程和使用分开。
比如需要通过if-else动态创建不同的子类对象,就可以考虑把if-else的判断逻辑放到工厂类中。
比如单个对象本身的创建过程比较复杂,需要组合其它对象,做各种初始化操作,也可以把这些逻辑封装到工厂类中。
⭐简单工厂
使用工厂模式实现解析不同格式的配置文件:
- 定义工厂类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16- public class RuleConfigParseFactory { 
 private static final Map<String, IRuleConfigParser> cachedParsers = new HashMap<>();
 static {
 cachedParsers.put("json", new JsonRuleConfigParser());
 cachedParsers.put("xml", new XmlRuleConfigParser());
 cachedParsers.put("yaml", new YamlRuleConfigParser());
 }
 
 public static IRuleConfigParser createParser(String configFormat) {
 if (configFormat == null || configFormat.isEmpty()) {
 return null;
 }
 IRuleConfigParser parser = cachedParser.get(configFormat);
 return parser;
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16- public class RuleConfigSource { 
 public RuleConfig load(String ruleConfigFilePath) {
 String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
 IRuleConfigParser parser = RuleConfigParserFactory.createParser(ruleConfigFileExtension);
 if (parser == null) {
 throw new InvalidRuleConfigException("Rule config file format is not support");
 }
 String configText = getFileContent();
 RuleConfig ruleConfig = parser.parse(configText);
 return ruleConfig;
 }
 private String getFileExtension(String filePath) {
 // ...获取文件拓展名,比如rule.json 返回json
 return "json";
 }
 }
⭐工厂方法
使用工厂模式实现解析不同格式的配置文件:
- 定义工厂方法类 - 1 
 2
 3- public interface IRuleConfigParserFactory { 
 IRuleConfigParser createPraser();
 }
- 具体的工厂类 - 1 
 2
 3
 4
 5
 6
 7- // json格式配置文件的工厂类 
 public class JsonRuleConfigParserFactory implements IRuleConfigParserFactory {
 
 public IRuleConfigParser createParser() {
 return new JsonRuleConfigParser();
 }
 }- 1 
 2
 3
 4
 5
 6
 7- // xml格式配置文件的工厂类 
 public class XmlRuleConfigParserFactory implements IRuleConfigParserFactory {
 
 public IRuleConfigParser createParser() {
 return new XmlRuleConfigParser();
 }
 }- 1 
 2
 3
 4
 5
 6
 7- // yaml格式配置文件的工厂类 
 public class YamlRuleConfigParserFactory implements IRuleConfigParserFactory {
 
 public IRuleConfigParser createParser() {
 return new YamlRuleConfigParser();
 }
 }
- 聚合工厂类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18- // 根据文件名后缀创建不同的工厂对象 
 public class RuleConfigParseFactory {
 private static final Map<String, IRuleConfigParserFactory> cachedParsers = new HashMap<>();
 static {
 cachedParsers.put("json", new JsonRuleConfigParserFactory());
 cachedParsers.put("xml", new XmlRuleConfigParserFactory());
 cachedParsers.put("yaml", new YamlRuleConfigParserFactory());
 }
 
 public static IRuleConfigParser createParser(String configFormat) {
 if (configFormat == null || configFormat.isEmpty()) {
 return null;
 }
 IRuleConfigParserFactory parserFactory = cachedParser.get(configFormat);
 IRuleConfigParser parser = parserFactory.createParser(); // 调用工厂方法获取具体的工厂类
 return parser;
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17- // 根据配置文件的后缀,将文件中的配置解析成内存对象 
 public class RuleConfigSource {
 public RuleConfig load(String ruleConfigFilePath) {
 String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
 IRuleConfigParser parser = RuleConfigParserFactory.createParser(ruleConfigFileExtension);
 if (parser == null) {
 throw new InvalidRuleConfigException("Rule config file format is not support: ");
 }
 String configText = getFileContent();
 RuleConfig ruleConfig = parser.parse(configText);
 return ruleConfig;
 }
 private String getFileExtension(String filePath) {
 // ...获取文件拓展名,比如rule.json 返回json
 return "json";
 }
 }
⭐抽象工厂
就是在工厂类中定义不同类型的对象的创建方式,可以减少工厂类的数量。
使用工厂模式实现解析不同格式的配置文件:
- 定义抽象工厂 - 1 
 2
 3
 4
 5
 6- public interface IConfigParserFactory { 
 // 创建rule配置文件解析器工厂类
 IRuleConfigParser createRuleParser();
 // 创建system配置文件解析器工厂类
 ISystemConfigParser createSystemParser();
 }
- 抽象工厂实现类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- public class JsonConfigParserFactory implements IConfigParserFactory { 
 // 创建json格式的rule配置文件解析器
 
 public IRuleConfigParser createRuleParser() {
 return new JsonRuleConfigParser();
 }
 
 // 创建json格式的system配置文件解析器
 
 public ISystemConfigParser createSystemParser() {
 return new JsonSystemConfigParser();
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- public class XmlConfigParserFactory implements IConfigParserFactory { 
 // 创建xml格式的rule配置文件解析器
 
 public IRuleConfigParser createRuleParser() {
 return new XmlRuleConfigParser();
 }
 
 // 创建xml格式的system配置文件解析器
 
 public ISystemConfigParser createSystemParser() {
 return new XmlSystemConfigParser();
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- public class YamlConfigParserFactory implements IConfigParserFactory { 
 // 创建yaml格式的rule配置文件解析器
 
 public IRuleConfigParser createRuleParser() {
 return new YamlRuleConfigParser();
 }
 // 创建yaml格式的system配置文件解析器
 
 public ISystemConfigParser createSystemParser() {
 return new YamlSystemConfigParser();
 }
 }
- 聚合工厂类 - 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- public class ConfigParserFactory { 
 private static final Map<String, IConfigParserFactory> map = new HashMap<>();
 static {
 map.put("json", new JsonConfigParserFactory());
 map.put("xml", new XmlConfigParserFactory());
 map.put("yaml", new YamlConfigParserFactory());
 }
 
 // 获取rule配置文件解析器
 public static IRuleConfigParser createRuleParser(String configFormat) {
 if (configFormat == null || configFormat.isEmpty()) {
 return null;
 }
 IConfigParserFactory factory = map.get(configFormat);
 IRuleConfigParser parser = factory.createRuleParser();
 return parser;
 }
 
 // 获取system配置文件解析器
 public static ISystemConfigParser createSystemParser(String configFormat) {
 if (configFormat == null || configFormat.isEmpty()) {
 return null;
 }
 IConfigParserFactory factory = map.get(configFormat);
 ISystemConfigParser parser = factory.createSystemParser();
 return parser;
 }
 }
单例模式(Singleton)
单例模式就是一个类只允许创建一个实例。
应用场景:
比如有些数据在系统中只应保存一份,就比较适合设计成单例类,比如用来保存系统配置的类,就比较适合设计成单例类。
比如某些系统中会缓存一些变动不太频繁的冷数据,通常就是在类中声明一些集合类型的成员变量用来缓存数据,这种也比较适合设计成单例类。
单例模式根据不同的创建方式,可以分细为五类:饿汉式、懒汉式、双重检测、静态内部类、枚举。
饿汉式
饿汉式就是在类加载的时候,就开始创建实例并初始化,这样的创建过程是线程安全的。
| 1 | public class Singleton { | 
有些人认为提前初始化实例是一种浪费资源的行为,应该等用到的时候再去初始化,不过如果初始化的逻辑比较复杂,耗时比较长,这就会影响到系统的性能。
用饿汉式把一些耗时的操作,提前到程序启动的时候完成,这样就能避免初始化的性能问题。
懒汉式
懒汉式可以实现延迟加载,就是在用到的时候,才去创建实例并初始化。
| 1 | public class Singleton { | 
但是在多线程环境中,饿汉式就需要通过加锁来确保只会创建一个实例,如果这个类经常被调用,就会导致频繁的加锁和解锁,会影响到系统的性能。
双重检测机制
双重检测也可以实现延迟加载,主要是为了解决,多线程环境下懒汉式并发度很低的问题。
| 1 | public class Singleton { | 
因为指令重排,可能会导致Singleton对象被new出来之后,还没来得及初始化,就被使用了。这个问题可以通过给成员变量加上volatile关键字,禁止指令重排。
实际上这个问题只有很低的JDK版本才会有,高版本的JDK内部已经解决了这个问题,就是把创建对象的new操作,和初始化操作设计为原子操作,就可以禁止指令重排。
静态内部类
静态内部类这种方式也可以实现延迟加载。
| 1 | public class Singleton { | 
静态内部类就是在类中定义一个静态内部类,在这个内部类中定义初始化的逻辑。当外部类被加载的时候,并不会创建内部类的实例对象,只有调用getInstance()方法的时候,内部类才会被加载,这个时候才会创建外部类的实例对象。
这个创建过程是由JVM来完成的,是线程安全的,也可以实现延迟加载。
枚举
基于枚举来实现单例,是最简单的一种方式了,就是通过Java枚举本身的特点,来保证实例创建的线程安全性和实例唯一性。
| 1 | public enum Singleton { | 
⭐建造者模式(Builder)
建造者模式主要是用来创建一些比较复杂的对象。
数据填充和校验
如果一个类中有很多属性,有些属性是必填的,有些是非必填的。比较简单的做法就是把必填属性放在构造函数中,其它非必填的用set()方法设置。如果必填的属性有很多,就会导致构造函数参数列表很长,使用起来就很容易出错。
- 写法 - 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- public class ResourcePoolConfig { 
 private String name;
 private int maxTotal;
 private int maxIdle;
 private int minIdle;
 
 private ResourcePoolConfig(Builder builder) {
 this.name = builder.name;
 this.maxTotal = builder.maxTotal;
 this.maxIdle = builder.maxIdle;
 this.minIdle = builder.minIdle;
 }
 
 // 通过Builder内部类完成属性填充
 public static class Builder {
 private String name;
 private int maxTotal;
 private int maxIdle;
 private int minIdle;
 
 public ResourcePoolConfig build() {
 // 对属性做校验
 if (StringUtils.isBlank(name)) {
 throw new IllegalArgumentException("name can't be empty");
 }
 return new ResourcePoolConfig(this);
 }
 
 public Builder setName(String name) {
 this.name = name;
 return this;
 }
 
 public Builder setMaxTotal(int maxTotal) {
 this.maxTotal = maxTotal;
 return this;
 }
 
 public Builder setMaxIdle(int maxIdle) {
 this.maxIdle = maxIdle;
 return this;
 }
 
 public Builder setMinIdle(int minIdle) {
 this.minIdle = minIdle;
 return this;
 }
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6
 7
 8- public static void main(String[] args) { 
 ResourcePoolConfig config = ResourcePoolConfig.Builder()
 .setName("test")
 .setMaxTotal(10)
 .setMaxIdle(5)
 .setMinIdle(2)
 .build();
 }
原型模式(Property)
如果一个对象的创建成本比较大,并且存在其它大部分字段都相同的对象,这种情况可以利用已有的对象,通过复制的方式来创建新的对象,这就叫原型模式。
原型模式有两种实现方法,深拷贝和浅拷贝。
- 浅拷贝只会复制对象中基本数据类型和引用对象的内存地址,不会递归的复制引用对象,以及引用对象的引用对象…。
- 深拷贝得到的是一份完全独立的对象,所以深拷贝会更加耗时,更耗内存空间。
实现缓存功能
很多时候我们会在系统启动的时候,从数据库中加载一些数据到内存中,用来做缓存。为了保证缓存中数据的正确性,通常会定期更新内存中的数据,这个时候就可以利用原型模式。
| 1 | public class Property { | 
⭐代理模式(Proxy)
就是在不修改原代码的情况下,通过代理类来给原始类附加额外的功能。
代理模式又分为:静态代理和动态代理。
⭐静态代理
为每个类都创建一个代理类,并且每个代理类都要把原始类中的方法实现一遍,再附加一些额外的代理逻辑。
- 原始类: - 1 
 2
 3
 4
 5- public class UserController { 
 public void login(String username, String password) {
 // 登录逻辑...
 }
 }
- 代理类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- public class UserControllerProxy { 
 private final UserController userController;
 
 public UserControllerProxy(UserController userController) {
 this.userController = userController;
 }
 
 public void login(String username, String password) {
 // 委托
 userController.login(username, password);
 // 添加一些额外的逻辑,比如登录成功后发送短信通知
 // ...
 }
 }
- 使用: - 1 
 2
 3
 4- public static void main(String[] args) { 
 UserControllerProxy userControllerProxy = new UserControllerProxy(new UserController());
 userControllerProxy.login("zhangsan","123456");
 }
⭐动态代理
就是不预先为每个类创建代理类,而是在运行的时候,动态的创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。
Java可以通过InvocationHandler接口和Proxy类来实现动态代理:
- 代理类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9- public class UserProxy { 
 public Object createProxy(Object proxyObject) {
 Class<?>[] interfaces = proxyObject.getClass().getInterfaces();
 // 创建动态代理处理器
 DynamicProxyHandler handler = new DynamicProxyHandler(proxyObject);
 // 创建代理类
 return Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(), interfaces);
 }
 }
- 动态代理处理器: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- public class DynamicProxyHandler implements InvocationHandler { 
 private Object proxyObject;
 
 public DynamicProxyHandler(Object proxyObject) {
 this.proxyObject = proxyObject;
 }
 
 
 public Object invoke(Object proxy, Method method, Object[] args) {
 // 代理逻辑...
 Object result = method.invoke(proxyObject, args);
 return result;
 }
 }
- 使用: - 1 
 2
 3
 4
 5- public static void main(String[] args) { 
 UserProxy proxy = new UserProxy();
 UserController userController = (UserController) proxy.createProxy(new UserController())
 userController.login();
 }
⭐桥接模式(Bridge)
将抽象部分和实现部分分离,让它们都可以独立的变化。
⭐消息推送功能
- 创建消息推送接口: - 1 
 2
 3- public interface MsgSender { 
 void send(String message);
 }
- 消息推送实现类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9- // 以短信的方式发送消息 
 public class TelephoneMsgSender implements MsgSender {
 private List<String> telephones;
 
 
 public void send(String message) {
 // 发送短信逻辑
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9- // 以邮件的方式发送消息 
 public class EmailMsgSender implements MsgSender {
 private List<String> emails;
 
 
 public void send(String message) {
 // 发送邮件逻辑
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9- // 以微信的方式发送消息 
 public class WechatMsgSender implements MsgSender {
 private List<String> wechats;
 
 
 public void send(String message) {
 // 发送微信逻辑
 }
 }
- 创建桥接类,根据消息的紧急程度,将消息发送到不同渠道(不同紧急程度的消息和发送渠道的对应关系,可以动态配置) - 定义消息通知抽象类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- public abstract class Notification { 
 // 消息发送渠道
 protected MsgSender msgSender;
 
 public Notification(MsgSender msgSender) {
 this.msgSender = msgSender;
 }
 
 public abstract void notify(String message);
 }
- 消息通知具体实现类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- // 严重通知级别 
 public class SevereNotification extends Notification {
 public SevereNotification(MsgSender msgSender) {
 super(msgSender);
 }
 
 
 public void notify(String message) {
 msgSender.send(message);
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- // 紧急通知级别 
 public class UrgencyNotification extends Notification {
 public UrgencyNotification(MsgSender msgSender) {
 super(msgSender);
 }
 
 
 public void notify(String message) {
 msgSender.send(message);
 }
 }
 
- 使用 - 1 
 2
 3
 4- public static void main(String[] args) { 
 Notification notifiaction = new UrgencyNotification(new EmailSender());
 notification.notify("这是一条紧急信息...");
 }
⭐装饰器模式(Decoreator)
装饰器模式跟代理模式的结构基本一样,只不过代理模式是为原始类增加一些额外的功能,装饰器模式是增强原始类现有的功能。
⭐增强登录功能
- 用户登录接口: - 1 
 2
 3- public interface LoginApi { 
 boolean login(String username, String password);
 }
- 原始类: - 1 
 2
 3
 4
 5
 6- public class LoginController implements LoginApi { 
 
 public boolean login(String username, String password) {
 // ...登录逻辑
 }
 }
- 发送邮件的装饰器: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18- // 登陆成功后发送邮件的装饰器 
 public class LoginControllerWithSendEmail implements LoginApi {
 private final LoginApi loginApi;
 private final Sender sender = new EmailSender(); // 发送邮件工具类
 public UserControllerWithSendEmail(LoginApi loginApi) {
 this.loginApi = loginApi;
 }
 
 
 public boolean login(String username, String password) {
 boolean result = loginApi.login(username, password);
 if (result) {
 // 登陆成功,发送邮件
 sender.send("登陆成功...");
 }
 return result;
 }
 }
- 生成登录记录的装饰器: - 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 class LoginControllerWithCreateRecord implements LoginApi {
 private final LoginApi loginApi;
 private final LoginRecordRepository loginRecordRepository = new LoginRecordRepository();
 
 public LoginControllerWithCreateRecord(LoginApi loginApi) {
 this.loginApi = loginApi;
 }
 
 
 public boolean login(String username, String password) {
 boolean result = loginApi.login(username, password);
 if (result) {
 // 创建一条登录信息
 LoginRecord loginRecord = LoginRecord.builder()
 .address("合肥")
 .ip("127.0.0.1")
 .timestamp(LocalDateTime.now())
 .build();
 loginRecordRepository.create(loginRecord);
 }
 return result;
 }
 
 }
- 使用: - 1 
 2
 3
 4
 5
 6
 7
 8- public static void main(String[] args) { 
 LoginApi loginApi = new LoginControllerWithCreateRecord(
 new LoginControllerWithSendEmail(
 new LoginController()
 )
 );
 loginApi.login("zhangsan","123456");
 }
⭐适配器模式(Adapter)
适配器模式就是用一个新类,把原来的类包装一下,用来解决两个不兼容的类可以在一起工作。
比如某个功能需要依赖多个外部系统,这些外部系统接口的参数和返回值格式都不一样,这时候就可以通过适配器模式,把它们的接口适配为统一的接口定义。
⭐数据聚合功能
- 从多种数据库查询数据: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20- //... 从mysql中获取数据 
 public class MySQLProvider {
 public List<String> find(String str1) {
 
 }
 }
 //.. 从Oracle中获取数据
 public class OracleProvider {
 public Map<String, String> find(String str1, String str2) {
 
 }
 }
 //... 从Redis中获取数据
 public class RedisProvider {
 public String get(String key) {
 
 }
 }
- 定义适配器接口: - 1 
 2
 3- public interface IDataProvider { 
 List<String> find(String param);
 }
- 根据不同的数据渠道定义不同的适配器: - 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 MySQLProviderAdapter implements IDataProvider { // MySQL适配器 
 private MySQLPrivider mysqlProvider = new MySQLProvider();
 
 public List<String> find(String str) {
 return mysqlProvider.find(str);
 }
 }
 public class OracleProviderAdapter implements IDataProvider { // Oracle适配器
 private OracleProvidedr oracleProvider = new OracleProvider();
 
 public List<String> find(String str) {
 Map<String, String> data = oracleProvider.find(str, "xxx");
 List<String> res = map2List(data);
 return res;
 }
 }
 public class RedisProvider implements IDataProvider { // Redis适配器
 private RedisProvider redisProvider = new RedisProvider();
 
 public List<String> find(String str) {
 String data = redisProvider.get(str);
 return Collections.singletonList(data);
 }
 }
- 聚合适配器: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- public class DataManagement { 
 private List<IDataProvider> providers = new ArrayList<>();
 public void addProvider(IDataProvider provider) {
 providers.add(provider);
 }
 public List<String> find(String str) {
 List<String> result = new ArrayList<>();
 for (IDataProvider provider : providers) {
 List<String> data = provider.find(str);
 result.addAll(data);
 }
 return result;
 }
 }
- 使用: - 1 
 2
 3
 4
 5
 6
 7
 8- public static void main(String[] args) { 
 // 使用
 DataManagement dataManagement = new DataManagement();
 dataManagement.addProvider(new MySQLProviderAdapter()); // 添加MySQL适配器
 dataManagement.addProvider(new OracleProviderAdapter()); // 添加Oracle适配器
 dataManagement.addProvider(new RedisProviderAdapter()); // 添加Redis适配器
 List<String> result = dataManagement.find("...");
 }
门面模式(Facade)
比如用户注册的时候,需要生成一条用户信息,还要给用户分配角色。这样注册这个功能就需要依赖,用户和角色两个服务。
传统的做法就是在用户注册服务中,依赖注入创建用户接口和分配角色接口。如果注册时还有更多的操作,就需要依赖更多的接口。
这种情况就可以定义一个门面服务,让门面服务去依赖用户服务和角色服务。这样注册服务只需要依赖门面服务就可以了。
提高效率:如果依赖的服务需要通过RPC调用,也可以通过门面模式把多次RPC调用减少为1次。
实现事物:有些时候需要调用两个更新数据的方法,这两个操作需要同时成功或者同时失败,最简单的方式就是:再设计一个包含这两个方法的新方法。这也是门面模式的一种设计思想。
实现用户注册功能
- 用户注册门面服务 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- public class UserRegisterFacade { 
 private final UserService userService;
 private final RoleService roleService;
 
 public void post(User user) {
 userService.create(user); // 创建用户
 roleService.setRole(user); // 分配角色
 }
 }
- 用户注册服务接口 - 1 
 2
 3
 4
 5
 6
 7
 8- public class SystemService { 
 private final UserRegisterFacade registerFacade;
 public boolean register(User user) {
 // 调用门面服务中的操作
 registerFacade.post(user);
 // 执行注册后续的操作...
 }
 }
⭐组合模式(Compose)
组合模式可以很方便的把不同类型的对象组合成树形结构。
⭐实现结构树
- 定义组织结构抽象类: - 1 
 2
 3
 4
 5
 6
 7- public abstract class Organization { // 用来做一些额外的处理逻辑 
 protected BigDecimal salary; // 工资
 protected int age; // 年龄
 public abstract BigDecimal calculateSalary(); // 计算部门所有工资总和(包括下级部门)
 public abstract int calculateAverageAge(); // 计算部门平均年龄
 public abstract boolean isDeparment(); // 是否是部门, 部门:true,员工:false
 }
- 部门类: - 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- public class Deparment implements Organization { 
 private long id;
 private String name;
 private List<Organization> subOrganizations = new ArrayList<>();
 
 public void addOrganization(Organization org) {
 subOrganizations.add(org);
 }
 
 
 public BigDecimal calculateSalary() {
 BigDecimal totalSalary = BigDecimal.ZERO;
 for (Organization org : subOrganizations) {
 totalSalary.add(org.getSalary());
 }
 return totalSalary;
 }
 
 
 public int calculateAverageAge() {
 int totalAge = 0;
 int employeeCount = 0;
 for (Organization org : subOrganizations) {
 if (!isDeparment()) {
 totalAge += org.getAge();
 employeeCount++;
 }
 }
 return totalAge / employeeCount;
 }
 
 public boolean isDeparment() {
 return true;
 }
 
 public BigDecimal getSalary() {
 BigDecimal totalSalary = BigDecimal.ZERO;
 for (Organization org : subOrganizations) {
 if (!org.isDepartment()) {
 totalSalary.add(org.getSalary());
 }
 }
 return totalSalary;
 }
 }
- 员工类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18- public class Employee implements Organization { 
 private long id;
 private String name;
 
 
 public BigDecimal calculateSalary() {
 return this.salary();
 }
 
 public int calculateAverageAge() {
 return this.age;
 }
 
 public boolean isDeparment() {
 return false;
 }
 
 }
- 使用: - 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- public static void main(String[] args) { 
 private DeparmentRepository deparmentRepo = new DeparmentRepository();
 private EmployeeRepository employeeRepo = new EmployeeRepository();
 private static final long ORGANIZATION_ROOT_ID = 1; // 顶级部门ID
 
 public void buildOrganization() {
 Deparment deparment = new Deparment();
 deparment.setId(ORGANIZATION_ROOT_ID);
 buildOrganization(deparment);
 }
 
 public void buildOrganization(Deparment deparment) {
 // 根据部门ID获取某个部门的下级部门
 List<Deparemnt> subDeparments = deparmentRepo.getDeparmentByParentId(deparment.getId());
 
 for (Deparment subDeparment : subDeparments) {
 deparment.addOrganization(subDeparment);
 buildOrganization(subDeparment);
 }
 
 // 根据部门ID获取员工列表
 List<Employee> employees = employeeRepo.getEmployeeByDeparmentId(deparment.getId());
 for (Employee employee : employees) {
 deparment.addOrganization(employee);
 }
 }
 
 }
⭐享元模式(Flyweight)
享元模式可以复用对象,节省内存,不过前提是享元对象是不可变的对象。
如果系统中有很多重复的对象,并且这些对象都是不可变的,就可以利用享元模式,让这些对象在内存中只保留一份,提供多处引用,这样可以减少内存中对象的数量。
也可以把对象之间相同的字段提取出来,设计成享元类,让这些对象引用享元对象。
不可变对象是指,对象通过构造函数初始化完成之后,就不能再做修改了,所以不能暴露任何set()方法,因为享元对象会被多处引用,如果某一个地方修改了享元对象,就会影响到其它代码。
比较常见的做法就是通过工厂模式,在工厂类中,用一个Map来缓存已经创建过的享元对象,来达到复用的目的。
比如Integer类中的IntegerCache、Long类中的LongCache也都是利用享元模式来预先存储一些常用的数字(-128~127)
缺点:享元模式会导致享元类无法被GC回收掉,因为享元工厂类会一直保存着享元对象的引用,这就会导致享元对象在没有任何代码使用的情况下,也不会被JVM回收掉。
⭐实现棋盘游戏
- 定义享元类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15- // 内部定义了一些通用的属性 
 public class ChessPieceUnit {
 private int id;
 private String text;
 private Color color;
 
 public ChessPieceUnit(int id, String text, Color color) {
 this.id = id;
 this.text = text;
 this.color = color;
 }
 public static enum Color {
 RED, BLACK
 }
 }
- 享元工厂类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- public class ChessPieceUnitFactory { 
 private static final Map<Integer, ChessPieceUnit> pieces = new HashMap<>();
 static {
 pieces.put(1, new ChessPieceUnit(1, "车", ChessPieceUnit.Color.BLACK));
 pieces.put(2, new ChessPieceUnit(2, "马", ChessPieceUnit.Color.BLACK));
 pieces.put(3, new ChessPieceUnit(3, "象", ChessPieceUnit.Color.BLACK));
 pieces.put(4, new ChessPieceUnit(4, "士", ChessPieceUnit.Color.BLACK));
 pieces.put(5, new ChessPieceUnit(5, "将", ChessPieceUnit.Color.BLACK));
 ...
 }
 public static ChessPieceUnit getChessPiece(int chessPieceId) {
 return pieces.get(chessPieceId);
 }
 }
- 棋子类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- public class ChessPiece { 
 private ChessPieceUnit chessPieceUnit; // 引用的享元类
 private int positionX; // 棋子在棋盘上的x坐标
 private int positionY; // 棋子在棋盘上的y坐标
 
 public ChessPiece(ChessPieceUnit chessPieceUnit, int positionX, int positionY) {
 this.chessPieceUnit = chessPieceUnit;
 this.positionX = positionX;
 this.positionY = positionY;
 }
 // getter/setter
 }
- 棋盘类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17- public class ChessBoard { 
 private Map<Integer, ChessPiece> chessPieces = new HashMap<>();
 public ChessBoard() {
 init();
 }
 
 private void init() {
 chessPieces.put(1,new ChessPiece(ChessPieceUnitFactory.getChessPiece(1), 0,0));
 chessPieces.put(2,new ChessPiece(ChessPieceUnitFactory.getChessPiece(2), 0,1));
 chessPieces.put(3,new ChessPiece(ChessPieceUnitFactory.getChessPiece(3), 0,2));
 chessPieces.put(4,new ChessPiece(ChessPieceUnitFactory.getChessPiece(4), 0,3));
 chessPieces.put(5,new ChessPiece(ChessPieceUnitFactory.getChessPiece(5), 0,4));
 }
 public void move(int chessPieceId, int toPositionX, int toPositionY) {
 // ...
 }
 }
⭐观察者模式(Observer)
就是在对象之间维护一个中间层,当一个对象状态改变的时候,其它所有依赖的对象都会自动收到通知。
guava包中的事件总线就是观察者模式(EventBus)
⭐实现注册功能
- 定义观察者接口: - 1 
 2
 3- public interface RegObserver { 
 void handleRegSuccess(long userId); // 用户注册成功时的事件通知函数
 }
- 定义观察者实现类: - 1 
 2
 3
 4
 5
 6
 7
 8- // 为新用户生成密码 
 public class RegPromotionObserver implements RegObserver {
 private PromotionService promitionService;
 
 public void handleRegSuccess(long userId) {
 promotionService.generatePassword(userId);
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8- // 发送欢迎邮件 
 public class RegNotificationObserver implements RegObserver {
 private NotificationService notificationService;
 
 public void handleRegSuccess(long userId) {
 notificationService.sendMessage(userId, "Welcome...");
 }
 }
- 用户注册接口: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17- public class UserController { 
 private UserService userService;
 // 观察者
 private List<RegObserver> regObservers;
 public void setRegObservers(List<RegObserver> observers) {
 regObservers = observers;
 }
 public void register(String telephone, String password) {
 // 用户注册
 long userId = userService.register(telephone, password);
 
 // 用户注册完成后,通知其它服务
 for (RegObserver observer : regObservers) {
 observer.handleRegSuccess(userId);
 }
 }
 }
- 使用: - 1 
 2
 3
 4
 5
 6
 7
 8
 9- public static void main(String[] args) { 
 List<RegObserver> regObservers = new ArrayList<>();
 regObservers.add(new RegNotificationObserver());
 regObservers.add(new RegPromotionObserver());
 
 UserController userController = new UserController();
 userController.setRegObservers(regObservers);
 userController.register("admin", "123456");
 }
用户注册完之后,要依次调用所有观察者的事件通知方法,都执行完,才会返回结果给客户端,这会影响到注册接口的响应时间。
可以改成异步非阻塞的方式,调用观察者的通知方法,比如在线程池中执行事件通知方法。
也可以用Event Bus(事件总线)框架,或者RocketMQ之类的消息队列。
⭐事件总线
- 定义标记注解,用来标明观察者中,哪个函数可以接收消息。 - 1 
 2
 3
 4
 public Subscribe {
 }
- 用来表示@Subscribe 标注的方法。target表示观察者类,method表示方法。主要用在ObserverRegistry观察者注册表中 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19- public class ObserverAction { 
 private Object target;
 private Method method;
 
 public ObserverAction(Object target, Method method) {
 this.target = Precondition.checkNotNull(target);
 this.method = method;
 this.method.setAccessable(true);
 }
 
 // event是method方法的参数
 public void execute(Object event) {
 try {
 method.invoke(target, event);
 } catch(Exception e) {
 e.printStackTrace();
 }
 }
 }
- 注册表 - 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- public class ObserverRegistry { 
 private ConcurrentMap<Class<?>, CopyOnWriteArraySet<ObserverAction>> registry = new ConcurrentHashMap<>();
 
 // 注册
 public void register(Object observer) {
 Map<Class<?>, Collection<ObserverAction> observerActions = findAllObserverActions(observer);
 for (Map.Entry<Class<?>, Collection<ObserverAction>> entry : observerActions.entrySet()) {
 Class<?> eventType = entry.getKey();
 Collection<ObserverAction> eventActions = entry.getValue();
 CopyOnWriteArraySet<ObserverAction> registeredEventActions = registry.get(eventType);
 if (registeredEventActions == null) {
 registry.putIfAbsent(eventType, new CopyOnWriteArraySet<>());
 registeredEventActions = registry.get(eventType);
 }
 registeredEventActions.addAll(eventActions);
 registry.put(eventType, registeredEventActions);
 }
 }
 
 // 找到符合条件的处理器
 public List<ObserverAction> getMatchedObserverActions(Object event) {
 List<ObserverAction> matchedObservers = new ArrayList<>();
 Class<?> postedEventType = event.getClass();
 for (Map.Entry<Class<?>, CopyOnWriteArraySet<ObserverAction>> entry : registry) {
 Class<?> eventType = entry.getKey();
 CopyOnWriteArraySet<ObserverAction> eventActions = entry.getValue();
 // 判断是否是父类
 if (postedEventType.isAssignableFrom(eventType)) {
 matchedObservers.addAll(eventActions);
 }
 }
 return matchedObservers;
 }
 
 private Map<Class<?>, Collection<ObserverAction>> findAllObserverActions(Object observer) {
 Map<Class<?>, Collection<ObserverAction>> observerActions = new HashMap<>();
 Class<?> clazz = observer.getClass();
 for (Method method : clazz.getDeclaredMethods() {
 if (method.isAnnotationPresent(Subscribe.class)) {
 Class<?>[] parameterTypes = method.getParameterTypes();
 if (parameterTypes.length != 1) {
 throw new ArgumentException("参数长度错误");
 }
 Class<?> eventType = parameterTypes[0];
 if (!observerActions.containsKey(eventType)) {
 observerActions.put(eventType, new ArrayList<>());
 }
 observerActions.get(eventType).add(new ObserverAction(observer, method));
 }
 }
 return observerActions;
 }
 
 }
- 事件总线 - 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- // 同步事件总线 
 public class EventBus {
 private Executor executor;
 private ObserverRegistry registry = new ObserverRegistry();
 
 public EventBus() {
 // MoreExecutors.directExecutor()是Google Guava提供的工具类,实际上是一个单线程的线程池,主要还是为了跟AsyncEventBus统一代码逻辑,做到代码复用。
 this(MoreExecutors.directExecutor());
 }
 
 protected EventBus(Executor executor) {
 this.executor = executor;
 }
 
 public void register(Object object) {
 registry.register(object);
 }
 
 public void post(Object event) {
 List<ObserverAction> observerActions = registry.getMatchedObserverActions(event);
 for (ObserverAction observerAction : observerActions) {
 executor.execute(new Runable() {
 
 public void run() {
 observerAction.execute(event);
 }
 });
 }
 }
 }- 1 
 2
 3
 4
 5
 6- // 异步事件总线 
 public class AsyncEventBus {
 public AsyncEventBus(Executor executor) {
 super(executor);
 }
 }
- 使用 - 1 
 2
 3
 4
 5- public static void main(String[] args) { 
 EventBus eventBus = new EventBus();
 eventBus.register(new RegNotificationObserver());
 eventBus.post("xxx");
 }
⭐模板模式(Template Method)
就是定义一个模板方法,规定业务流程,让子类来实现流程的业务逻辑。
在Java中,通常是把模板方法定义成final的,避免被子类重写,需要子类重写的方法,定义为abstract的,强迫子类实现。
可以提高代码的复用性和拓展性。
JDK中有很多类都用到了模板模式,比如InputStream、OutputStream、Reader、Writer。
InputStream中read()方法就是一个模板方法,规定了读取数据的流程,而且还暴露了一个重载的抽象方法,让子类来实现读取数据的逻辑。
AbstractList中addAll()也是一个模板方法,需要依赖子类重写add()方法才能调用。
⭐模板模式结构
- 定义模板类和模板方法 - 1 
 2
 3
 4
 5
 6
 7
 8- public abstract class AbstractTemplate { 
 public final void templateMethod() { // 定义模板方法,规定业务流程
 f1();
 f2();
 }
 public abstract void f1(); // 流程1
 public abstract void f2(); // 流程2
 }
- 定义子类实现流程1和流程2的逻辑 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- public class Concrete1 extends AbstractTemplate { 
 
 public void f1() {
 //...
 }
 
 public void f2() {
 //...
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- public class Concrete2 extends AbstractTemplate { 
 
 public void f1() {
 //...
 }
 
 public void f2() {
 //...
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6
 7- public static void main(String[] args) { 
 AbstractTemplate template = new Concreate1();
 template.templateMethod();
 
 template = new Concreate2();
 template.templateMethod();
 }
⭐策略模式(Strategy)
就是定义一个策略接口,然后再根据不同的逻辑定义一些实现这个接口的策略类。这样就可以很灵活的替换不同的策略。
策略模式一般都会通过类型,来判断创建哪个策略来使用,可以可以配合工厂模式,把创建策略的逻辑放到工厂类中。
如果策略类是无状态的,不包含成员变量,这样的策略对象是可以共享的,不需要每次都创建新的对象,可以预先创建好策略对象,缓存到工厂类中。
⭐策略模式结构
- 定义策略接口: - 1 
 2
 3- public interface Strategy { 
 void method();
 }
- 定义策略实现类: - 1 
 2
 3
 4
 5
 6
 7- // 策略类1 
 public class ConcreteStrategyA implements Strategy {
 
 public void method() {
 // 具体的逻辑...
 }
 }- 1 
 2
 3
 4
 5
 6
 7- // 策略类2 
 public class ConcreteStrategyB implements Strategy {
 
 public void method() {
 // 具体的逻辑...
 }
 }
- 定义策略工厂类: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- // 定义策略工厂类,用来创建具体的策略 
 public class StrategyFactory {
 private static final Map<String, Strategy> strategies = new HashMap<>(); // 用来缓存策略对象
 static {
 strategies.put("A", new ConcreteStrategyA());
 strategies.put("B", new ConcreteStrategyB());
 }
 
 public static Strategy getStrategy(String type) {
 return strategies.get(type);
 }
 
 }
- 使用: - 1 
 2
 3
 4- public static void main(String[] args) { 
 Strategy strategy = StrategyFactory.getStrategy("A");
 strategy.method();
 }
⭐责任链模式(Chain Of Responsibility)
就是多个类处理同一个请求,一个请求先经过A处理,然后再把请求传递给B处理,B再传递给C处理。每个类都承担着自己的职责。
Servlet中的Filter和Spring中的Interceptor都使用了责任链模式。
⭐实现过滤敏感信息功能
- 定义敏感信息过滤接口 - 1 
 2
 3- public interface SensitiveFilter { 
 boolean doFilter(Content content);
 }
- 根据数据类型定义不同的过滤器 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- // 文本过滤器 
 public class SensitiveTextFilter implements SensitiveFilter {
 
 public boolean doFilter(Content content) {
 boolean legal = true;
 // 判断用户输入的文本是否包含敏感词汇
 return legal;
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9- // 图片过滤器 
 public class SensitiveImageFilter implements SensitiveFilter {
 
 public boolean doFilter(Content content) {
 boolean legal = true;
 // 判断用户上传的图片是否包含敏感信息
 return legal;
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9- // 视频过滤器 
 public class SensitiveVideoFilter implements SensitiveFilter {
 
 public boolean doFilter(Content content) {
 boolean legal = true;
 // 判断用户上传的视频是否包含敏感信息
 return legal;
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9- // 音频过滤器 
 public class SensitiveAudioFilter implements SensitiveFilter {
 
 public boolean doFilter(Content content) {
 boolean legal = true;
 // 判断用户上传的音频是否包含敏感信息
 return legal;
 }
 }
- 定义责任链类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17- public class SensitiveFilterChain { 
 // 过滤器
 private List<SensitiveFilter> filters = new ArrayList<>();
 
 public void addFilter(SensitiveFilter filter) {
 this.filters.add(filter);
 }
 
 public boolean filter(Content content) {
 for (SensitiveFilter filter : filters) {
 if (!filter.doFilter(content)) {
 return false;
 }
 }
 return true;
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- public static void main(Stirng[] args) { 
 SensitiveFilterChain filterChain = new SensitiveFilterChain();
 filterChain.addFilter(new SensitiveTextFilter());
 filterChain.addFilter(new SensitiveImageFilter());
 filterChain.addFilter(new SensitiveVideoFilter());
 filterChain.addFilter(new SensitiveAudioFilter());
 
 boolean legal = filterChain.filter(new Content());
 if (legal) {
 // 合法
 } else {
 // 不合法
 }
 }
⭐状态模式(Finite State Machine)
状态模式就是把,事件触发的状态转移和执行动作,拆分到不同的类中。
⭐超级马里奥游戏
- 定义马里奥接口 - 1 
 2
 3
 4
 5
 6
 7
 8- public interface IMario { 
 // 定义事件
 void obtainMushroom(); // 获得蘑菇事件
 void obtainCape(); // 获得斗篷事件
 void obtainFireFlower(); // 获得火焰花事件
 void meetMonster(); // 遇到怪物事件
 void topBrick(); // 顶砖头事件
 }
- 马里奥实现类,并根据马里奥状态重写事件逻辑 - 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- // 小马里奥 
 public class SmallMario implements IMario {
 private MarioStateMachine marioStateMachine;
 
 public SmallMario(MarioStateMachine marioStateMachine) {
 this.marioStateMachine = marioStateMachine;
 }
 
 public void obtainMushroom() {
 //小马里奥获得蘑菇,变为超级马里奥
 marioStateMachine.setState(new SuperMario(marioStateMachine));
 }
 
 public void obtainCape() {
 // 小马里奥获得斗篷,变成斗篷马里奥
 marioStateMachine.setState(new CapeMario(marioStateMachine));
 }
 
 public void obtainFireFlower() {
 // 小马里奥获得火焰花,变成火焰马里奥
 marioStateMachine.setState(new FireMario(marioStateMachine));
 }
 
 public void meetMonster() {
 // 小马里奥遇到怪物,减少一条命
 marioStateMachine.descreaseLife();
 }
 
 public void topBrick() {
 // 小马里奥顶砖头,不会破坏砖头
 
 }
 }- 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- // 超级马里奥 
 public class SuperMario implements IMario {
 private MarioStateMachine marioStateMachine;
 
 public SuperMario(MarioStateMachine marioStateMachine) {
 this.marioStateMachine = marioStateMachine;
 }
 
 
 public void obtainMushroom() {
 // 超级马里奥获得蘑菇,积分加100
 marioStateMachine.increaseScore(100);
 }
 
 public void obtainCape() {
 // 超级马里奥获得斗篷,变成斗篷马里奥
 marioStateMachine.setState(new CapeMario(marioStateMachine));
 }
 
 public void obtainFireFlower() {
 // 超级马里奥获得火焰花,变成火焰马里奥
 marioStateMachine.setState(new FireMario(marioStateMachine));
 }
 
 public void meetMonster() {
 // 超级马里奥遇到怪物,变成小马里奥
 marioStateMachine.setState(new SmallMario(marioStateMachine));
 }
 
 public void topBrick() {
 // 超级马里奥顶砖头,会破坏砖头
 marioStateMachine.distoryBrick();
 }
 
 }
- 定义状态机 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- public class MarioStateMachine { 
 private IMario currentMario;
 
 public MarioStateMachine() {
 currentMario = new SmallMario(this); //默认是小马里奥
 }
 
 public void setState(IMario mario) {
 currentMario = mario;
 }
 public IMario getState() {
 return this.currentMario;
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6- public static void main(String[] args) { 
 MarioStateMachine marioStateMachine = new MarioStateMachine();
 marioStateMachine.obtainMushroom(); // 吃蘑菇
 marioStateMachine.topBrick(); // 顶砖头
 marioStateMachine.getState();
 }
迭代器模式(Iterator)
迭代器模式就是用来遍历集合的,它会把集合的遍历操作从集合类中拆分出来,放到迭代器类中,让双方的职责更单一。
foreach循环是一个语法糖,底层是基于迭代器来实现的。
for循环比较适合遍历数组、链表这种线性数据结构。对于复杂的数据结构,比如树、图,树有前中后序、按层遍历,图有深度优先、广度优先遍历。使用迭代器模式就可以针对深度优先和广度优先,定义两个迭代器,分别实现深度优先和广度优先。
基于快照的迭代器
为每个元素保存两个时间戳,一个是添加时间addTimestamp,另一个是删除时间delTimestamp。
当元素被加入到集合的时候,addTimestamp = 当前时间、delTimestamp = Long.MAX_VALUE。
当元素被删除的时候,delTimestamp = 当前时间。表示已经被删除。
再定义一个快照的创建时间 snapshotTimestamp。只有addTimestamp < snapshotTimestamp < delTimestamp 的元素才属于当前快照。
如果元素的添加时间大于快照的创建时间,说明元素是在快照之后才加入的,不属于当前快照。
如果元素的删除时间小于快照的创建时间,说明元素在快照之前就被删除掉了,也不属于当前快照。
- 定义ArrayList - 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- public class ArrayList<E> implements List<E> { 
 private static final int DEFAULT_CAPACITY = 10;
 
 private int actualSize; // 不包含标记删除的元素。
 private int totalSize; // 包含标记删除的元素
 
 private Object[] elements;
 private long[] addTimestamps;
 private long[] delTimestamps;
 
 public ArrayList() {
 this.elements = new Object[DEFAULT_CAPACITY];
 this.addTimestamps = new long[DEFAULT_CAPACITY];
 this.delTimestamps = new long[DEFAULT_CAPACITY];
 this.actualSize = 0;
 this.totalSize = 0;
 }
 
 public Iterator iterator() {
 return new SnapshotArrayIterator(this);
 }
 
 
 public void add(E obj) {
 elements[totalSize] = obj;
 addTimestamps[totalSize] = System.currentTimeMills();
 delTimestamps[totalSize] = Long.MAX_VALUE;
 totalSize++;
 actualSize++;
 }
 
 
 public void remove(E obj) {
 for (int i = 0; i < totalSize; i++) {
 if (elements[i].equals(obj)) {
 delTimestamps[i] = System.currentTimeMills();
 actualSize--;
 }
 }
 }
 
 
 public E get(int i) {
 if (i >= totalSize) {
 throw new IndexOutOfBoundsException();
 }
 return (E) elements[i];
 }
 
 }
- 定义迭代器 - 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- public class SnapshotArrayIterator<E> implements Iterator<E> { 
 private long snapshotTimestamp;
 private int cursorInAll; // 在整个容器中的下标,而非快照中的下标
 private int leftCount; // 快照中还有几个元素未被遍历
 private ArrayList<E> arrayList;
 
 public SnapshotArrayIterator(ArrayList<E> arrayList) {
 this.snapshotTimestamp = System.currentTimeMills();
 this.cursorInAll = 0;
 this.leftCount = arrayList.actualSize();
 this.arrayList = arrayList;
 
 justNext(); //先跳到这个迭代器快照的第一个元素
 }
 
 
 public boolean hasNext() {
 return this.leftCount >= 0;
 }
 
 
 public E next() {
 E currentItem = arrayList.get(cursorInAll);
 justNext();
 return currentItem;
 }
 
 private void justNext() {
 while(cursorInAll < arrayList.totalSize()) {
 long addTimestamp = arrayList.getAddTimestmap(cursorInAll);
 long delTimestamp = arrayList.getDelTimestamp(cursorInALl);
 if (snapshotTimestamp > addTimestamp && snapshotTimestamp < delTimestamp) {
 leftCount--;
 break;
 }
 cursorInAll++;
 }
 }
 }
访问者模式(Visitor Pattern)
访问者模式针对的是一组不同类型的对象,但是这组对象需要继承相同的父类。为了避免不断添加新功能导致类不断膨胀,可以使用访问者模式将对象与业务逻辑解耦,可以把这些业务逻辑抽离出来,定义在访问者类中。
实现文件解析和压缩功能
- 定义文件父类 - 1 
 2
 3
 4
 5
 6
 7- public abstract class ResourceFile { 
 protected String filePath;
 public ResourceFile(String filePath) {
 this.filePath = filePath;
 }
 public abstract void accept(Visitor visitor);
 }
- 根据文件类型定义不同的文件实现类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- // PDF文件 
 public class PdfFile extends ResourceFile {
 public PdfFile(String filePath) {
 super(filePath);
 }
 
 public void accept(Visitor visitor) {
 visitor.visit(this);
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- // PPT文件 
 public class PPTFile extends ResourceFile {
 public PPTFile(String filePath) {
 super(filePath);
 }
 
 public void accept(Visitor visitor) {
 visitor.visit(this);
 }
 }
- 定义访问者接口 - 1 
 2
 3
 4
 5
 6- // 访问者 
 public interface Visitor {
 void visit(PdfFile pdfFile);
 void visit(PPTFile pptFile);
 void visit(WordFile wordFile);
 }
- 定义访问者实现类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15- // 提取文件内容访问者 
 public class Extractor implements Visitor {
 
 public void visit(PdfFile pdfFile) {
 // 将pdf提取到txt文本
 }
 
 public void visit(PPTFile pptFile) {
 // 将ppt提取到txt文本
 }
 
 public void visit(WordFile wordFile) {
 // 将word提取到txt文本
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15- // 压缩文件访问者 
 public class Compressor implements Visitor {
 
 public void visit(PdfFile pdfFile) {
 // 压缩pdf文件
 }
 
 public void visit(PPTFile pptFile) {
 // 压缩ppt文件
 }
 
 public void visit(WordFile wordFile) {
 // 压缩word文件
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24- // 使用 
 public class ToolApplication {
 public static void main(String[] args) {
 Extactor extractor = new Extractor();
 List<ResourceFile> resourceFiles = listAllResourceFiles(new File("D:/test/"));
 for (ResourceFile file : resourceFiles) {
 file.accept(extractor); // 提取文件内容
 }
 Compressor compressor = new Compressor();
 for (ResourceFile file : resourceFiles) {
 file.accept(compressor); // 压缩文件
 }
 }
 
 public List<ResourceFile> listAllResourceFiles(File resourceDirectory) {
 List<ResourceFile> resourceFiles = new ArrayList<>();
 File[] files = resourceDirectory.listFiles();
 for(File file : files) {
 ResourceFile resourceFile = ResourceFileFactory.createResourceFile(file);
 resourceFiles.add(resourceFile);
 }
 return resourceFiles;
 }
 }
备忘录模式(Memento)
在不违背封装原则的前提下,获取并保存一个对象的内部状态,以便之后恢复对象为之前的状态。
备忘录模式主要分为两部分:一部分是存储副本以便后期恢复,另一部分是在不违反封装原则的前提下,进行对象备份和恢复。
比如在很多文本编辑器中,使用Ctrl+Z可以撤销上一次输入的文本,这样的场景就可以使用备忘录模式。
实现文本编辑器
- 定义文本对象 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16- // 用来存储用户输入的所有文本内容 
 public class InputText {
 private StringBuilder text = new StringBuilder();
 
 public String getText() {
 return text.toString();
 }
 
 public void append(String input) {
 text.append(input);
 }
 
 public void restoreSnapshot(Snapshot snapshot) {
 this.text.replace(0, this.text.length(), snapshot.getText());
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- // 用户输入的文本对象 
 public class Snapshot {
 private String text;
 public Snapshot(String text) {
 this.text = text;
 }
 public String getText() {
 return text;
 }
 }
- 保存用户输入的文本副本的容器 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- public class SnapshotHolder { 
 private Stack<Snapshot> snapshots = new Stack<>(); // 用来存储每次用户输入的文本对象的副本
 public Snapshot popSnapshot() {
 return snapshots.pop();
 }
 public void pushSnapshot(Snapshot snapshot) {
 snapshots.push(snapshot);
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15- public static void main(String[] args) { 
 InputTtext inputText = new InputText();
 SnapshotHolder snapshotHolder = new SnapshotHolder();
 Scanner scanner = new Scanner(System.in);
 while (scanner.hasNext()) {
 String input = scanner.next();
 if ("ctrl+z".equals(input)) {
 Snapshot snapshot = snapshotHolder.popSnapshot();
 inputText.restoreSnapshot(snapshot);
 } else {
 inputText.append(input);
 snapshotHolder.pushSnapshot(new Snapshot(input));
 }
 }
 }
命令模式(Command)
命令模式就是,将函数封装成一个对象,这样就可以把函数当成变量一样传递来传递去。
基本结构
- 定义命令接口 - 1 
 2
 3- public interface Command { 
 void execute();
 }
- 命令实现类 - 1 
 2
 3
 4
 5
 6
 7- // 眩晕敌人 
 public class FaintEnemyCommand implements Command {
 
 public void execute() {
 }
 }- 1 
 2
 3
 4
 5
 6
 7- // 攻击敌人 
 public class AttackEnemyCommand implements Command {
 
 public void execute() {
 }
 }
- 命令执行器 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- public class Invoker { 
 private Queue<Command> commands = new LinkedList<>();
 public void addCommand(Command command) {
 commands.add(command);
 }
 public void executeCommands() {
 while (!commands.isEmpty()) {
 Command command = commands.poll();
 command.execute();
 }
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6- public static voids main(String[] args) { 
 Invoker invoke = new Invoker();
 invoke.addCommand(new FaintEnemyCommand()); // 添加眩晕敌人的命令
 invoke.addCommand(new AttackEnemyCommand()); // 添加攻击敌人的命令
 invoke.executeCommands(); // 执行所有命令
 }
⭐解释器模式(Interpreter)
解释器模式可以用来为某个语言定义它的语法,并定义 一个解释器来处理语法。
⭐实现表达式解析器
- 定义解析器接口 - 1 
 2
 3- public interface Expression { 
 boolean interpret(Map<String, Long> stats);
 }
- 解析器实现类 - 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 static class GreaterExpression implements Expression {
 private final String key;
 private final long value;
 public GreaterExpression(String key, long value) {
 this.key = key;
 this.value = value;
 }
 public GreaterExpression(String strExpression) {
 String[] elements = strExpression.trim().split("\\s+");
 if (elements.length > 3 || !elements[1].trim().equals(">")) {
 throw new RuntimeException("...");
 }
 this.key = elements[0].trim();
 this.value = Long.parseLong(elements[2].trim());
 }
 
 public boolean interpret(Map<String, Long> stats) {
 if (!stats.containsKey(key)) {
 return false;
 }
 long statValue = stats.get(key);
 return statValue > value;
 }
 }- 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 class LessExpression implements Expression {
 private final String key;
 private final long value;
 public LessExpression(String key, long value) {
 this.key = key;
 this.value = value;
 }
 public LessExpression(String strExpression) {
 String[] elements = strExpression.trim().split("\\s+");
 if (elements.length < 3 || !elements[1].trim().equals("<")) {
 throw new RuntimeException("...");
 }
 this.key = elements[0].trim();
 this.value = Long.parseLong(elements[2].trim());
 }
 
 public boolean interpret(Map<String, Long> stats) {
 if (!stats.containsKey(key)) {
 return false;
 }
 Long statValue = stats.get(key);
 return statValue < value;
 }
 }- 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 class EqualsExpression implements Expression {
 private final String key;
 private final long value;
 public EqualsExpression(String key, long value) {
 this.key = key;
 this.value = value;
 }
 public EqualsExpression(String strExpression) {
 String[] elements = strExpression.trim().split("\\s+");
 if (elements.length < 3 || !elements[1].trim().equals("==")) {
 throw new RuntimeException("...");
 }
 this.key = elements[0].trim();
 this.value = Long.parseLong(elements[2].trim());
 }
 
 public boolean interpret(Map<String, Long> stats) {
 if (!stats.containsKey(key)) {
 return false;
 }
 Long statValue = stats.get(key);
 return statValue == value;
 }
 }- 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- // and解析器 
 public static class AndExpression implements Expression {
 private List<Expression> expressions = new ArrayList<>();
 public AndExpression(List<Expression> expressions) {
 this.expressions = expressions;
 }
 public AndExpression(String strExpression) {
 String[] elements = strExpression.split("&&");
 for (String str : elements) {
 if (str.contains(">")) {
 expressions.add(new GreaterExpression(str));
 } else if (str.contains("<")) {
 expressions.add(new LessExpression(str));
 } else if (str.contains("==")) {
 expressions.add(new EqualsExpression(str));
 } else {
 throw new RuntimeException("...");
 }
 }
 }
 
 public boolean interpret(Map<String, Long> stats) {
 for (Expression expression : expressions) {
 if (!expression.interpret(stats)) {
 return false;
 }
 }
 return true;
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22- // or解析器 
 public static class OrExpression implements Expression {
 private List<Expression> expressions = new ArrayList<>();
 public OrExpression(List<Expression> expressions) {
 this.expressions = expressions;
 }
 public OrExpression(String strExpression) {
 String[] strExpressions = strExpression.split("\\|\\|");
 for (String expr : strExpressions) {
 expressions.add(new AndExpression(expr));
 }
 }
 
 public boolean interpret(Map<String, Long> stats) {
 for (Expression expr : expressions) {
 if (expr.interpret(stats)) {
 return true;
 }
 }
 return false;
 }
 }
- 解析器入口 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- public static class AlertRuleInterpret { 
 private final Expression expression;
 public AlertRuleInterpret(String ruleExpression) {
 this.expression = new OrExpression(ruleExpression);
 }
 public boolean interpret(Map<String, Long> stats) {
 return expression.interpret(stats);
 }
 }
- 使用 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- // 使用 
 public static void main(String[] args) {
 String rule = "key1 > 100 || key2 == 50 && key3 == 30";
 Map<String, Long> stats = new HashMap<>();
 stats.put("key1", 100L);
 stats.put("key2", 50L);
 stats.put("key3", 20L);
 stats.put("key4", 80L);
 AlertRuleInterpret alertRuleInterpret = new AlertRuleInterpret(rule);
 boolean result = alertRuleInterpret.interpret(stats);
 System.out.println(result);
 }
中介模式(Mediator)
中介模式就是把,一组对象之间的依赖关系,从多对多,转换成一对多。微服务中的注册中心,就可以理解为是一种中介模式。
实现UI控制器
- 定义中介接口 - 1 
 2
 3- public interface Mediator { 
 void handleEvent(Component component, Event event);
 }
- 定义中介实现类 - 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- public class LandingPageDialog implements Mediator { 
 private Button loginButton;
 private Button registerButton;
 private Input usernameInput;
 private Input passwordInput;
 private Selection selection;
 
 
 public void handleEvent(Componment component, Event event) {
 if (component.equals(loginButton)) {
 String username = usernameInput.text();
 String password = passwordInput.text();
 // ...
 } else if (component.equals(registerButton)) {
 String username = usernameInput.text();
 String password = passwordInput.text();
 // 校验数据
 // 业务处理
 } else if (component.equals(selection)) {
 String selectionItem = selection.select();
 if (selectionItem.equals("login")) {
 usernameInput.show();
 passwordInput.show();
 // ...
 }
 }
 }
 
 }
- 使用 - 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- public class UIControl { 
 private static final String LOGIN_BUTTON_ID = "login_button";
 private static final String REGISTER_BUTTON_ID = "register_button";
 private static final String USERNAME_INPUT_ID = "username_input";
 private static final String PASSWORD_INPUT_ID = "password_input";
 private static final String SELECTION_ID = "selection";
 public static void main(String[] args) {
 Button loginButton = (Button) findComponmentById(LOGIN_BUTTON_ID);
 Button registerButton = (Button) findComponmentById(REGISTER_BUTTON_ID);
 Input usernameInput = (Input) findComponmentById(USERNAME_INPUT_ID);
 Input passwordInput = (Input) findComponmentById(PASSWORD_INPUT_ID);
 Selection selection = (Selection) findComponmentById(SELECTION_ID);
 
 Mediator dialog = new LandingPageDialog();
 dialog.setLoginButton(loginButton);
 dialog.setRegisterButton(registerButton);
 dialog.setUsernameInput(usernameInput);
 dialog.setPasswordInput(passwordInput);
 dialog.setSelection(selection);
 
 loginButton.setOnClickListener(new OnClickListener() {
 
 public void onClick() {
 dialog.handleEvent(loginButton, Event.CLICK);
 }
 });
 registerButton.setOnClickListener(new OnClickListener() {
 
 public void onClick() {
 dialog.handleEvent(registerButton, Event.REGISTER);
 }
 });
 
 
 }
 }
 
        