当前位置: 首页 > news >正文

青岛网站设计哪家便宜上海百度竞价点击软件

青岛网站设计哪家便宜,上海百度竞价点击软件,电商设计类插画,企业网站一般用什么程序做文章目录 一、定义:观察者模式二、模拟场景:观察者模式2.1 观察者模式2.2 引入依赖2.3 工程结构2.4 模拟摇号2.4.1 摇号服务接口2.4.2 摇号返回结果类 三、违背方案:观察者模式3.0 引入依赖3.1 工程结构3.2 添加摇号接口和实现3.2.1 摇号服务…

文章目录

  • 一、定义:观察者模式
  • 二、模拟场景:观察者模式
    • 2.1 观察者模式
    • 2.2 引入依赖
    • 2.3 工程结构
    • 2.4 模拟摇号
      • 2.4.1 摇号服务接口
      • 2.4.2 摇号返回结果类
  • 三、违背方案:观察者模式
    • 3.0 引入依赖
    • 3.1 工程结构
    • 3.2 添加摇号接口和实现
      • 3.2.1 摇号服务接口
      • 3.2.2 摇号服务接口实现类
    • 3.3 单元测试
  • 四、改善代码:观察者模式
    • 4.0 引入依赖
    • 4.1 工程结构
    • 4.2 观察者模式结构图
    • 4.3 添加事件监听和管理器
      • 4.3.1 定义事件监听接口
      • 4.3.2 短信息事件监听接口实现
      • 4.3.3 MQ发送事件监听接口实现
      • 4.3.4 事件处理器
    • 4.4 摇号抽象类及其实现
      • 4.4.1 业务抽象类
      • 4.4.2 业务接口实现类
    • 4.5 单元测试
  • 五、总结:观察者模式

一、定义:观察者模式

在这里插入图片描述

  • **观察者模式:**当一个行为发生时传递信息给另外一个用户接收做出相应的处理,两者之间没有直接的耦合关联。
  • 除了生活中的场景外,在我们编程开发中也会常用到一些观察者的模式或者组件。例如:
    • 经常使用的 MQ 服务:虽然 MQ 服务是有一个通知中心并不是每一个类服务进行通知,但整体上也可以算作是观察者模式的思路设计。
    • 类似事件监听总线:让主线服务与其他辅线业务分离,为了使系统降低耦合和增强扩展性,也会使用观察者模式进行处理。

二、模拟场景:观察者模式

2.1 观察者模式

请添加图片描述

  • 模拟每次小客车指标摇号事件通知场景
  • 可能大部分人看到这个案例一定会想到自己每次摇号都不中的场景,收到一个遗憾的短信通知。当然目前的摇号系统不会给你发短信,而是由百度或者一些其他插件发的短信。
  • 那么假如这个类似的摇号功能由你来开发,并且需要对外部的用户做一些事件通知以及需要在主流外再添加一些额外的辅助流程时该如何处理呢?
    • 基本很多人对于这样的通知事件类的实现往往比较粗犷,直接在类里面添加就可以了。
      • ①考虑这可能不会怎么扩展,②是压根就没考虑过扩展。
    • 但如果你有仔细思考过你的核心类功能会发现,这里面有一些核心主链路,还有一部分是辅助功能。
      • 比如完成了某个行为后需要触发 MQ 给外部,以及做一些消息 PUSH 给用户等。
      • 这些都不算做是核心流程链路,是可以通过事件通知的方式进行处理。

2.2 引入依赖

pom.xml

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.62</version></dependency><!-- LOGGING begin --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.5</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>1.7.5</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.0.9</version><exclusions><exclusion><artifactId>slf4j-api</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency>
</dependencies>

2.3 工程结构

design-19.0-0
|——src|——main|--java|--com.lino.design|-LotteryResult.java|-MinibusTargetService.java

2.4 模拟摇号

2.4.1 摇号服务接口

MinibusTargetService.java

package com.lino.design;/*** @description: 小客车指标调控服务*/
public class MinibusTargetService {/*** 模拟摇号** @param uId 用户编号* @return 结果*/public String lottery(String uId) {return Math.abs(uId.hashCode()) % 2 == 0 ?"恭喜你,编码".concat(uId).concat("在本次摇号中签"): "很遗憾,编码".concat(uId).concat("在本次摇号未中签或摇号资格已过期");}
}

2.4.2 摇号返回结果类

LotteryResult.java

package com.lino.design;import java.util.Date;/*** @description: 摇号结果类*/
public class LotteryResult {/*** 用户ID*/private String uId;/*** 摇号信息*/private String msg;/*** 业务时间*/private Date dateTime;public LotteryResult(String uId, String msg, Date dateTime) {this.uId = uId;this.msg = msg;this.dateTime = dateTime;}public String getuId() {return uId;}public void setuId(String uId) {this.uId = uId;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Date getDateTime() {return dateTime;}public void setDateTime(Date dateTime) {this.dateTime = dateTime;}
}

三、违背方案:观察者模式

按照需求需要在原有的摇号接口中添加 MQ 消息发送以及短信息通知功能。
如果是最直接的方式那么可以直接在方法中补充功能即可。

3.0 引入依赖

<dependencies><dependency><groupId>com.lino</groupId><artifactId>design-19.0-0</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>

3.1 工程结构

design-19.0-1
|——src|——main|--java|--com.lino.design|-LotteryService.java|-LotteryServiceImpl.java|--test|--com.lino.design.test|-ApiTest.java

3.2 添加摇号接口和实现

3.2.1 摇号服务接口

LotteryService.java

package com.lino.design;/*** @description: 摇号接口*/
public interface LotteryService {/*** 摇号** @param uId 用户编号* @return 摇号结果*/LotteryResult doDraw(String uId);
}

3.2.2 摇号服务接口实现类

LotteryServiceImpl.java

package com.lino.design;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;/*** @description: 摇号接口实现类*/
public class LotteryServiceImpl implements LotteryService {private Logger logger = LoggerFactory.getLogger(LotteryServiceImpl.class);private MinibusTargetService minibusTargetService = new MinibusTargetService();@Overridepublic LotteryResult doDraw(String uId) {// 摇号String lottery = minibusTargetService.lottery(uId);// 发短信logger.info("给用户 {} 发送短信通知(短信):{}", uId, lottery);// 发MQ信息logger.info("记录用户 {} 摇号结果(MQ):{}", uId, lottery);return new LotteryResult(uId, lottery, new Date());}
}
  • 从上面的方法实现中可以看到,整体过程包括三部分:摇号、发短信、发 MQ 消息,而这部分都是顺序调用的。
  • 除了 摇号 接口调用外,后面的两部分都是非核心主链路功能,而且会随着后续的业务需求发展而不断的调整和扩充,在这样的开发方式下就非常不利于维护。

3.3 单元测试

ApiTest.java

package com.lino.design.test;import com.alibaba.fastjson.JSON;
import com.lino.design.LotteryResult;
import com.lino.design.LotteryService;
import com.lino.design.LotteryServiceImpl;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: 单元测试*/
public class ApiTest {private Logger logger = LoggerFactory.getLogger(ApiTest.class);@Testpublic void test() {LotteryService lotteryService = new LotteryServiceImpl();LotteryResult result = lotteryService.doDraw("2765789109876");logger.info("测试结果:{}", JSON.toJSONString(result));}
}
  • 测试过程中提供对摇号服务接口的调用

测试结果

17:06:14.931 [main] INFO  com.lino.design.LotteryServiceImpl - 给用户 2765789109876 发送短信通知(短信):很遗憾,编码2765789109876在本次摇号未中签或摇号资格已过期
17:06:14.931 [main] INFO  com.lino.design.LotteryServiceImpl - 记录用户 2765789109876 摇号结果(MQ):很遗憾,编码2765789109876在本次摇号未中签或摇号资格已过期
17:06:15.122 [main] INFO  com.lino.design.test.ApiTest - 测试结果:{"dateTime":1675760774946,"msg":"很遗憾,编码2765789109876在本次摇号未中签或摇号资格已过期","uId":"2765789109876"}

四、改善代码:观察者模式

4.0 引入依赖

<dependencies><dependency><groupId>com.lino</groupId><artifactId>design-19.0-0</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>

4.1 工程结构

design-19.0-2
|——src|——main|--java|--com.lino.design|--event|		|--listener|		|		|--EventListener.java|		|		|--MessageEventListener.java|		|		|--MQEventListener.java|		|--EventManager.java|-LotteryService.java|-LotteryServiceImpl.java|--test|--com.lino.design.test|-ApiTest.java

4.2 观察者模式结构图

请添加图片描述

  • 从上图可以分为三大块:事件监听、事件处理、具体的业务流程。
    • 另外在业务流程中 LotteryService 定义的是抽象类,因为这样可以通过抽象类将事件功能屏蔽,外部业务流程开发者不需要知道具体的通知操作。
  • 右下角圆圈图表示的是核心流程与非核心流程的结构。
    • 一般在开发中会把主线流程开发完成后,再使用通知的方式处理辅助流程。他们可以是异步的,在 MQ 以及定时任务的处理下,保证最终一致性。

4.3 添加事件监听和管理器

4.3.1 定义事件监听接口

EventListener.java

package com.lino.design.event.listener;import com.lino.design.LotteryResult;/*** @description: 事件监听接口*/
public interface EventListener {/*** 监听事件** @param result 摇号结果*/void doEvent(LotteryResult result);
}
  • 接口定义了基本的事件类,这里如果方法的入参信息类型是变化的,可以使用泛型 T

4.3.2 短信息事件监听接口实现

MessageEventListener.java

package com.lino.design.event.listener;import com.lino.design.LotteryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: 短消息事件监听实现*/
public class MessageEventListener implements EventListener {private Logger logger = LoggerFactory.getLogger(MessageEventListener.class);@Overridepublic void doEvent(LotteryResult result) {logger.info("给用户 {} 发送短信通知(短信):{}", result.getuId(), result.getMsg());}
}

4.3.3 MQ发送事件监听接口实现

MQEventListener.java

package com.lino.design.event.listener;import com.lino.design.LotteryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: MQ事件监听实现*/
public class MQEventListener implements EventListener {private Logger logger = LoggerFactory.getLogger(MQEventListener.class);@Overridepublic void doEvent(LotteryResult result) {logger.info("记录用户 {} 摇号结果(MQ):{}", result.getuId(), result.getMsg());}
}

4.3.4 事件处理器

EventManager.java

package com.lino.design.event;import com.lino.design.LotteryResult;
import com.lino.design.event.listener.EventListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @description: 事件处理器*/
public class EventManager {Map<Enum<EventType>, List<EventListener>> listeners = new HashMap<>();public EventManager(Enum<EventType>... operations) {for (Enum<EventType> operation : operations) {this.listeners.put(operation, new ArrayList<>());}}public enum EventType {/*** 事件类型*/MQ, Message}/*** 订阅** @param eventType 事件类型* @param listener  监听*/public void subscribe(Enum<EventType> eventType, EventListener listener) {List<EventListener> users = listeners.get(eventType);users.add(listener);}/*** 取消订阅** @param eventType 事件类型* @param listener  监听*/public void unsubscribe(Enum<EventType> eventType, EventListener listener) {List<EventListener> users = listeners.get(eventType);users.remove(listener);}/*** 通知** @param eventType 事件类型* @param result    结果*/public void notify(Enum<EventType> eventType, LotteryResult result) {List<EventListener> users = listeners.get(eventType);for (EventListener listener : users) {listener.doEvent(result);}}
}
  • 整个处理的实现上提供了三个主要方法:订阅 subscribe 、取消订阅 unsubscribe 、通知 notify 。这三个方法分别用于对监听事件的添加和使用。
  • 另外因为事件有不同的类型,这里使用率枚举的方式进行处理,也方便让外部在规定下使用事件,而不至于乱传信息。
    • 枚举:EventType.MQEventType.Message

4.4 摇号抽象类及其实现

4.4.1 业务抽象类

LotteryService.java

package com.lino.design;import com.lino.design.event.EventManager;
import com.lino.design.event.listener.MQEventListener;
import com.lino.design.event.listener.MessageEventListener;/*** @description: 摇号抽象类*/
public abstract class LotteryService {private EventManager eventManager;public LotteryService() {eventManager = new EventManager(EventManager.EventType.MQ, EventManager.EventType.Message);eventManager.subscribe(EventManager.EventType.MQ, new MQEventListener());eventManager.subscribe(EventManager.EventType.Message, new MessageEventListener());}public LotteryResult draw(String uId) {LotteryResult lotteryResult = doDraw(uId);eventManager.notify(EventManager.EventType.MQ, lotteryResult);eventManager.notify(EventManager.EventType.Message, lotteryResult);return lotteryResult;}/*** 执行摇号** @param uId 用户编号* @return 结果*/protected abstract LotteryResult doDraw(String uId);
}
  • 使用抽象类的方式定义实现方法,可以在方法中扩展需要的额外调用。
    • 并提供抽象类 abstract LotteryResult doDraw(String uId) ,让类的继承者实现。
    • 同时,方法的定义使用的是 protected ,也就是保证将来外部的调用方不会调用到此方法,只有调用到 draw(String uId) 才能完成事件通知。
  • 此种方式到实现是在抽象类中写好一个基本的方法,在方法中完成新增逻辑到同时,再增加抽象类的使用,而这个抽象的定义会由继承者实现。
  • 另外,在构造函数中提供了对事件的定义:
    • eventManager.subscribe(EventManager.EventType.MQ, new MQEventListener())
    • 在使用时也采用枚举的方式通知使用者,传了哪些类型 eventManager.EventType.Message,就执行哪些事件通知,按需添加。

4.4.2 业务接口实现类

LotteryServiceImpl.java

package com.lino.design;import java.util.Date;/*** @description: 摇号服务实现* @author: lingjian* @createDate: 2023/2/6 17:02*/
public class LotteryServiceImpl extends LotteryService {private MinibusTargetService minibusTargetService = new MinibusTargetService();@Overrideprotected LotteryResult doDraw(String uId) {// 摇号String lottery = minibusTargetService.lottery(uId);// 结果return new LotteryResult(uId, lottery, new Date());}
}
  • 业务流程的实现,没有额外的辅助流程,只有核心流程的处理。

4.5 单元测试

ApiTest.java

package com.lino.design.test;import com.alibaba.fastjson.JSON;
import com.lino.design.LotteryResult;
import com.lino.design.LotteryService;
import com.lino.design.LotteryServiceImpl;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: 单元测试*/
public class ApiTest {private Logger logger = LoggerFactory.getLogger(ApiTest.class);@Testpublic void test_draw() {LotteryService lotteryService = new LotteryServiceImpl();LotteryResult result = lotteryService.draw("1000000101010019");logger.info("测试结果:{}", JSON.toJSONString(result));}
}

测试结果

19:45:45.314 [main] INFO  c.l.d.event.listener.MQEventListener - 记录用户 1000000101010019 摇号结果(MQ):恭喜你,编码1000000101010019在本次摇号中签
19:45:45.319 [main] INFO  c.l.d.e.l.MessageEventListener - 给用户 1000000101010019 发送短信通知(短信):恭喜你,编码1000000101010019在本次摇号中签
19:45:45.398 [main] INFO  com.lino.design.test.ApiTest - 测试结果:{"dateTime":1675770345311,"msg":"恭喜你,编码1000000101010019在本次摇号中签","uId":"1000000101010019"}

五、总结:观察者模式

  • 从基本的过程式开发,到使用观察者模式面向对象开发,可以看到使用设计模式改造后,拆分出来核心流程与辅助流程的代码。
    • 代码中的核心流程一般不会发生经常变化,辅助流程会随着业务的变化而变化,包括营销、裂变和促活等。
    • 因此使用设计模式编码就显得非常有必要。
  • 观察者模式从结构上满足开闭原则,当需要新增其他的监听事件或修改监听逻辑时,不需要改动事件处理类。
  • 观察者模式可能不能控制调用顺序以及需要做一些事件结果的返回操作,所以在使用的过程时需要考虑场景的适用性。
http://www.zhongyajixie.com/news/6573.html

相关文章:

  • 两个网站做反向代理网站代运营推广
  • 外国网站建设拓客app下载
  • angularjs做的网站有哪些湖人最新消息
  • wordpress批量添加tag南京seo全网营销
  • 火星建站和八亿建站北京百度seo公司
  • 物业公司网站模板优化大师是干什么的
  • 温州网站建设平台软文营销广告案例
  • 万网网站备案免费发布友链
  • 荣成城乡建设局网站今日军事新闻报道
  • 太原小店区最新消息今天seo外链怎么做
  • 剑网三奇遇查询网站怎么做济南市最新消息
  • 网站开发需求列表天眼查询个人
  • 手机网站建设的方法推广平台有哪些渠道
  • 手机网站制作天强科技短视频seo推广
  • 自己的网站怎么做砍价产品优化是什么意思
  • 广州企业如何建网站莆田seo
  • 大数据做网站湖南正规关键词优化
  • 企业网站的策划书seo外包优化公司
  • 黄冈网站建设费用外链工具软件
  • 网站做简介如何发布自己的html网站
  • b2b免费平台3天网站seo优化成为超级品牌
  • 做网站主要学什么条件新手怎样做网络推广
  • 济宁b2b网站建设服务站长之家ppt素材
  • 网站后台管理系统php长沙营销网站建设
  • 樟木头网站推广整合营销策划方案模板
  • 学商务网站建设的感想海外免费网站推广
  • 成都黑帽seo黑帽seo联系方式
  • 医院网站建设 中企动力怎样建立网站免费的
  • 无锡网站推广经理经典网络营销案例
  • 做网站霸屏公司销售好做吗b站视频推广