模板方法
1.什么是模板方法模式
2.模板方法模式应用场景
3.分布式锁代码使用模板方法重构
4.什么是观察者模式?
5.观察者模式应用场景
6.spring事件监听观察者模式原理分析
20点25分准时开始
什么是模板方法
1.定义了一个操作中的算法的骨架,而将部分步骤的实现在子类中完成。
模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
2.模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术,没有关联关系。 因此,在模板方法模式的类结构图中,只有继承关系。
核心设计要点:
AbstractClass : 抽象类,定义并实现一个模板方法。这个模板方法定义了算法的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类去实现
ConcreteClass : 实现实现父类所定义的一个或多个抽象方法。
一般模板方法是结合策略模式一起使用。
因为策略模式,相同的事情,但是有不同的策略实现
模版方法应用场景
\1. 聚合支付系统异步回调、QQ联合登录、对接第三方短信接口、分布式锁实现、jdbc模板
\2. Servlet 请求
对接第三方短信接口
对接阿里云 、华为云、腾讯云 相同事情存放在骨架中(抽象类中 交给子类具体发送)
kafka、rocketmq
kafka
amqpTemplate—执行发送投递消息kafka
rabbitmq
amqpTemplate—执行发送投递消息rabbitmq
分布式锁有哪些实现方式
1.zk分布式锁
2.redis分布式锁
3.数据库分布式锁
分布式锁 获取锁、释放锁
class ZkLock{
tryLock(){
Long startTime = System.currentTimeMillis();
获取锁-------zk获取锁具体流程
Long endTime = System.currentTimeMillis();
获取锁时间endTime-startTime
}
}
class RedisLock{
tryLock(){
Long startTime = System.currentTimeMillis();
获取锁-------redis获取锁具体流程
Long endTime = System.currentTimeMillis();
获取锁时间endTime-startTime
}
}
模板重构 有共同的骨架,骨架中有些部分细节不一样 使用模板方法设计模式重构。
模式模式优缺点
1.)优点
模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。子类实现算法的某些细节,有助于算法的扩展。通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
2.)缺点
每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
3.)适用场景
在某些类的算法中,用了相同的方法,造成代码的重复。控制子类扩展,子类必须遵守算法规则。
模板方法设计模式 配合抽象类实现
发送短信、查询物流快递—
相同的代码存放—抽象类中。
相关代码
共同骨架
package com.mayikt.lock;
import lombok.extern.slf4j.Slf4j;
/**
* @author 余胜军
* @ClassName AbstractDistributedLock
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
public abstract class DistributedLockTemplate {
/**
* 获取锁方法
*/
public void lock() {
Long startTime = System.currentTimeMillis();
tryLock();
Long endTime = System.currentTimeMillis();
log.info("<获取锁时间,>" + (endTime - startTime));
}
protected abstract void tryLock();
/**
* 释放锁方法
*/
public void unLock() {
Long startTime = System.currentTimeMillis();
tryUnLock();
Long endTime = System.currentTimeMillis();
log.info("<释放锁时间,>" + (endTime - startTime));
}
protected abstract void tryUnLock();
}
具体实现
package com.mayikt.lock.impl;
import com.mayikt.lock.DistributedLockTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author 余胜军
* @ClassName RedisDistributedLockTemplate
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
@Component
public class ZkDistributedLockTemplate extends DistributedLockTemplate {
@Override
protected void tryLock() {
try {
Thread.sleep(5);
} catch (Exception e) {
}
log.info("<zk方法实现获取锁!>");
}
@Override
protected void tryUnLock() {
try {
Thread.sleep(3);
} catch (Exception e) {
}
log.info("<zk方法实现释放锁!>");
}
}
package com.mayikt.lock.impl;
import com.mayikt.lock.DistributedLockTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author 余胜军
* @ClassName RedisDistributedLockTemplate
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
@Component
public class RedisDistributedLockTemplate extends DistributedLockTemplate {
@Override
protected void tryLock() {
try {
Thread.sleep(10);
} catch (Exception e) {
}
log.info("<redis方法实现获取锁!>");
}
@Override
protected void tryUnLock() {
try {
Thread.sleep(15);
} catch (Exception e) {
}
log.info("<redis方法实现释放锁!>");
}
}
模板工厂
package com.mayikt.lock.factory;
import com.mayikt.lock.DistributedLockTemplate;
import com.mayikt.lock.utils.SpringUtils;
public class TemplateFactory {
public static DistributedLockTemplate getPayCallbackTemplate(String templateId) {
DistributedLockTemplate payCallbackTemplate = (DistributedLockTemplate) SpringUtils.getBean(templateId);
return payCallbackTemplate;
}
}
访问测试
package com.mayikt.lock.service;
import com.mayikt.lock.DistributedLockTemplate;
import com.mayikt.lock.factory.TemplateFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 余胜军
* @ClassName LockTestService
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@RestController
@Slf4j
public class LockTestService {
@RequestMapping("/lockTest")
public String lockTest(String templateId) {
DistributedLockTemplate payCallbackTemplate = TemplateFactory.getPayCallbackTemplate(templateId);
try {
payCallbackTemplate.lock();
log.info("<lockTest>");
payCallbackTemplate.unLock();
return "ok";
} catch (Exception e) {
payCallbackTemplate.unLock();
return "error";
}
}
}
观察者模式
什么是观察者模式
1.在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
2.其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。
观察者模式应用场景
Zookeeper事件通知节点、消息订阅通知、安卓开发事件注册、分布式配置中心
观察者模式原理类图
1.抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者角色,一般用一个抽象类和接口来实现。
2.抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
3.具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
4.具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
观察者模式模式简单实现
抽象观察者
package com.mayikt.observer;
/**
* @author 余胜军
* @ClassName ObServer
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public interface ObServer {
/**
* 抽象观察者
*/
void update(String message);
}
具体观察者
package com.mayikt.observer.impl;
import com.mayikt.observer.ObServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author 余胜军
* @ClassName UserObServerImpl
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
public class UserObServerImpl implements ObServer {
private String name;
public UserObServerImpl(String name) {
this.name = name;
}
@Override
public void update(String message) {
log.info("<name:{},message:{}>", name, message);
}
}
抽象主题
package com.mayikt.subject;
import com.mayikt.observer.ObServer;
/**
* @author 余胜军
* @ClassName AbstractSubject
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public interface AbstractSubject {
/**
* 添加addObServer
*/
void addObServer(ObServer obServer);
/**
* removeObServer
*/
void removeObServer(ObServer obServer);
/**
* notifyObServerAll
*/
void notifyObServerAll(String message);
void setNotifyObServerAll(String message);
}
具体主题
package com.mayikt.subject.impl;
import com.mayikt.observer.ObServer;
import com.mayikt.subject.AbstractSubject;
import java.util.ArrayList;
import java.util.List;
/**
* @author 余胜军
* @ClassName WeChatSubjectImpl
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class WeChatSubjectImpl implements AbstractSubject {
private List<ObServer> obServers = new ArrayList<ObServer>();
private String message;
@Override
public void addObServer(ObServer obServer) {
obServers.add(obServer);
}
@Override
public void removeObServer(ObServer obServer) {
obServers.remove(obServer);
}
@Override
public void notifyObServerAll(String message) {
obServers.forEach(obServer -> {
obServer.update(message);
});
}
@Override
public void setNotifyObServerAll(String message) {
this.message = message;
notifyObServerAll(message);
}
}
测试代码
package com.mayikt;
import com.mayikt.observer.impl.UserObServerImpl;
import com.mayikt.subject.AbstractSubject;
import com.mayikt.subject.impl.WeChatSubjectImpl;
/**
* @author 余胜军
* @ClassName Test01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class Test01 {
public static void main(String[] args) {
// 1.注册主题
AbstractSubject abstractSubject = new WeChatSubjectImpl();
abstractSubject.addObServer(new UserObServerImpl("小敏"));
abstractSubject.addObServer(new UserObServerImpl("小薇"));
abstractSubject.setNotifyObServerAll("mayikt666");
}
}
D:\path\jdk\jdk8\jdk\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:59115,suspend=y,server=n -javaagent:C:\Users\mayikt\AppData\Local\JetBrains\IntelliJIdea2020.2\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\path\jdk\jdk8\jdk\jre\lib\charsets.jar;D:\path\jdk\jdk8\jdk\jre\lib\deploy.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\access-bridge-64.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\cldrdata.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\dnsns.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\jaccess.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\jfxrt.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\localedata.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\nashorn.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunec.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunjce_provider.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunmscapi.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\sunpkcs11.jar;D:\path\jdk\jdk8\jdk\jre\lib\ext\zipfs.jar;D:\path\jdk\jdk8\jdk\jre\lib\javaws.jar;D:\path\jdk\jdk8\jdk\jre\lib\jce.jar;D:\path\jdk\jdk8\jdk\jre\lib\jfr.jar;D:\path\jdk\jdk8\jdk\jre\lib\jfxswt.jar;D:\path\jdk\jdk8\jdk\jre\lib\jsse.jar;D:\path\jdk\jdk8\jdk\jre\lib\management-agent.jar;D:\path\jdk\jdk8\jdk\jre\lib\plugin.jar;D:\path\jdk\jdk8\jdk\jre\lib\resources.jar;D:\path\jdk\jdk8\jdk\jre\lib\rt.jar;D:\data\mayikt-designmode\mayikt-observer\target\classes;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-web\2.2.3.RELEASE\spring-boot-starter-web-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter\2.2.3.RELEASE\spring-boot-starter-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot\2.2.3.RELEASE\spring-boot-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-autoconfigure\2.2.3.RELEASE\spring-boot-autoconfigure-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-logging\2.2.3.RELEASE\spring-boot-starter-logging-2.2.3.RELEASE.jar;D:\maven\mvnRespo\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\mvnRespo\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\mvnRespo\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\maven\mvnRespo\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;D:\maven\mvnRespo\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;D:\maven\mvnRespo\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\maven\mvnRespo\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\maven\mvnRespo\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-json\2.2.3.RELEASE\spring-boot-starter-json-2.2.3.RELEASE.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-databind\2.10.2\jackson-databind-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-annotations\2.10.2\jackson-annotations-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\core\jackson-core\2.10.2\jackson-core-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.2\jackson-datatype-jdk8-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.2\jackson-datatype-jsr310-2.10.2.jar;D:\maven\mvnRespo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.2\jackson-module-parameter-names-2.10.2.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-tomcat\2.2.3.RELEASE\spring-boot-starter-tomcat-2.2.3.RELEASE.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-core\9.0.30\tomcat-embed-core-9.0.30.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-el\9.0.30\tomcat-embed-el-9.0.30.jar;D:\maven\mvnRespo\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.30\tomcat-embed-websocket-9.0.30.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-validation\2.2.3.RELEASE\spring-boot-starter-validation-2.2.3.RELEASE.jar;D:\maven\mvnRespo\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\maven\mvnRespo\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;D:\maven\mvnRespo\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;D:\maven\mvnRespo\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\maven\mvnRespo\org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-webmvc\5.2.3.RELEASE\spring-webmvc-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-aop\5.2.3.RELEASE\spring-aop-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-context\5.2.3.RELEASE\spring-context-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-expression\5.2.3.RELEASE\spring-expression-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\projectlombok\lombok\1.18.10\lombok-1.18.10.jar;D:\maven\mvnRespo\com\alibaba\fastjson\1.2.73\fastjson-1.2.73.jar;D:\maven\mvnRespo\org\mybatis\spring\boot\mybatis-spring-boot-starter\1.1.1\mybatis-spring-boot-starter-1.1.1.jar;D:\maven\mvnRespo\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\1.1.1\mybatis-spring-boot-autoconfigure-1.1.1.jar;D:\maven\mvnRespo\org\mybatis\mybatis\3.4.0\mybatis-3.4.0.jar;D:\maven\mvnRespo\org\mybatis\mybatis-spring\1.3.0\mybatis-spring-1.3.0.jar;D:\maven\mvnRespo\org\springframework\boot\spring-boot-starter-jdbc\2.2.3.RELEASE\spring-boot-starter-jdbc-2.2.3.RELEASE.jar;D:\maven\mvnRespo\com\zaxxer\HikariCP\3.4.2\HikariCP-3.4.2.jar;D:\maven\mvnRespo\org\springframework\spring-jdbc\5.2.3.RELEASE\spring-jdbc-5.2.3.RELEASE.jar;D:\maven\mvnRespo\org\springframework\spring-tx\5.2.3.RELEASE\spring-tx-5.2.3.RELEASE.jar;D:\maven\mvnRespo\mysql\mysql-connector-java\8.0.19\mysql-connector-java-8.0.19.jar;D:\idea-mayikt\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar" com.mayikt.Test01
Connected to the target VM, address: '127.0.0.1:59115', transport: 'socket'
19:49:57.638 [main] INFO com.mayikt.observer.impl.UserObServerImpl - <name:小敏,message:mayikt666>
19:49:57.905 [main] INFO com.mayikt.observer.impl.UserObServerImpl - <name:小薇,message:mayikt666>
Disconnected from the target VM, address: '127.0.0.1:59115', transport: 'socket'
Process finished with exit code 0
JDK自带观察实现消息发送
(1). Observable类追踪所有的观察者,并通知他们。
(2). Observer这个接口看起来很熟悉,它和我们之前写的类几乎一样。
package com.mayikt.jdk;
import java.util.Observable;
public class MessageObServable extends Observable {
@Override
public void notifyObservers(Object arg) {
// 1.改变数据
setChanged();
// 2.通知所有的观察者改变
super.notifyObservers(arg);
}
}
package com.mayikt.jdk;
import lombok.extern.slf4j.Slf4j;
import java.util.Observable;
import java.util.Observer;
@Slf4j
public class EmailObServer implements Observer {
public void update(Observable o, Object arg) {
// 1.获取主题
MessageObServable messageObServable = (MessageObServable) o;
log.info("发送邮件内容:" + arg);
}
}
package com.mayikt.jdk;
import lombok.extern.slf4j.Slf4j;
import java.util.Observable;
import java.util.Observer;
@Slf4j
public class SmsObServer implements Observer {
public void update(Observable o, Object arg) {
log.info("发送短信内容:" + arg);
}
}
package com.mayikt.jdk;
import com.alibaba.fastjson.JSONObject;
public class JdkObServer {
public static void main(String[] args) {
//1.创建主题
MessageObServable messageObServable = new MessageObServable();
// 2.添加订阅者
messageObServable.addObserver(new EmailObServer());
messageObServable.addObserver(new SmsObServer());
// 3.组装消息内容
JSONObject jsonObject = new JSONObject();
jsonObject.put("email", "644064779@qq.com");
jsonObject.put("phone", "15123456789");
jsonObject.put("text", "恭喜您以1399.00元购买蚂蚁课堂永久会员.");
messageObServable.notifyObservers(jsonObject.toJSONString());
}
}
Spring封装事件监听
Spring实现事件通知,底层才观察者模式封装的
package com.mayikt.listener;
import org.springframework.context.ApplicationEvent;
/**
* @author 余胜军
* @ClassName OrderCreateEvent
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class OrderCreateEvent extends ApplicationEvent {
private String json;
public OrderCreateEvent(Object source, String json) {
super(source);
this.json = json;
}
public String getJson() {
return json;
}
public void setJson(String json) {
this.json = json;
}
}
package com.mayikt.listener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @author 余胜军
* @ClassName EmailListener
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Component
@Slf4j
public class EmailListener implements ApplicationListener<OrderCreateEvent> {
@Override
public void onApplicationEvent(OrderCreateEvent event) {
log.info("<发送邮件,{}>", event.getJson());
}
}
package com.mayikt.listener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @author 余胜军
* @ClassName EmailListener
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Component
@Slf4j
public class SmsListener implements ApplicationListener<OrderCreateEvent> {
@Override
public void onApplicationEvent(OrderCreateEvent event) {
log.info("<发送短信,{}>", event.getJson());
}
}
package com.mayikt.service;
import com.alibaba.fastjson.JSONObject;
import com.mayikt.listener.OrderCreateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 余胜军
* @ClassName OrderService
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@RestController
@Slf4j
public class OrderService {
@Autowired
private ApplicationContext applicationContext;
@RequestMapping("/addOrder")
public String addOrder() {
log.info("<创建订单>");
// 3.组装消息内容
JSONObject jsonObject = new JSONObject();
jsonObject.put("email", "644064779@qq.com");
jsonObject.put("phone", "15123456789");
jsonObject.put("text", "恭喜您以1399.00元购买蚂蚁课堂永久会员.");
OrderCreateEvent orderCreateEvent = new OrderCreateEvent(this, jsonObject.toJSONString());
applicationContext.publishEvent(orderCreateEvent);
return "success";
}
}