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

网站项目建设计划网站诊断博客

网站项目建设计划,网站诊断博客,怎么改网站内容,wordpress kindeditor生产环境中常用的设计模式 设计模式目的使用场景示例单例模式保证一个类仅有一个实例#xff0c;并提供一个访问它的全局访问点- 日志记录器- 配置管理器工厂方法模式定义一个创建对象的接口#xff0c;让子类决定实例化哪个类- 各种工厂类#xff08;如视频游戏工厂模式创…生产环境中常用的设计模式 设计模式目的使用场景示例单例模式保证一个类仅有一个实例并提供一个访问它的全局访问点- 日志记录器- 配置管理器工厂方法模式定义一个创建对象的接口让子类决定实例化哪个类- 各种工厂类如视频游戏工厂模式创建不同类型的角色抽象工厂模式解决一个系列的工厂用于创建一组相关或依赖的对象- GUI组件库- 汽车组装线建造者模式分离对象的构建过程和表示允许逐步构造一个复杂对象- 构建复杂对象如SQL语句构建器原型模式通过复制现有的实例来创建新的实例- 需要频繁创建开销较大的对象时适配器模式将不兼容的接口转换为一个可以使用的兼容接口- 兼容旧的类库- 第三方库的集成桥接模式分离抽象部分和实现部分使它们可以独立地变化- 当一个类存在多个变化维度时组合模式将对象组合成树形结构以表示“部分-整体”的层次结构- 处理类似文件系统的层次结构装饰器模式动态地添加额外功能到一个对象而不是通过继承- 扩展对象功能而不改变其类外观模式为子系统中的一组接口提供一个统一的接口- 简化复杂的系统接口享元模式运用共享技术有效支持大量细粒度对象- 当系统中存在大量相似对象时代理模式为其他对象提供一个代理或占位符以控制对该对象的访问- 访问控制- 延迟初始化责任链模式使多个对象都有机会处理请求避免耦合请求的发送者和接收者- 审批流程- 错误处理命令模式将一个请求封装为一个对象允许使用不同的请求参数化其他对象- 宏系统- 事务系统解释器模式定义一个语言的文法并建立解释器解释该语言中的句子- 解析表达式或指令迭代器模式提供一种顺序访问聚合对象元素的方法而不暴露其内部表示- 遍历聚合对象而不关心内部结构中介者模式用一个中介对象封装一系列对象之间的交互- 集中管理对象间的通信备忘录模式捕获对象的内部状态并在外部保存该状态- 提供对象状态快照用于撤销操作观察者模式对象间存在一对多关系时使用- 事件多级触发- 发布/订阅系统状态模式对象在其内部状态改变时可改变行为- 行为随状态改变而变化的对象策略模式定义一系列算法并将它们封装起来使其可以互换- 运行时动态选择算法访问者模式在不改变类前提下定义作用于对象结构的新操作- 数据结构稳定但需定义新操作 Spring 容器的作用与使用 Spring 容器是 Spring 框架的核心组件之一用于管理 Java 对象的生命周期和依赖关系。它以 IoC控制反转 和 DI依赖注入 为核心思想帮助开发者简化对象的创建、配置、管理及其依赖关系。 1. Spring 容器的核心概念 控制反转IoC 传统编程中对象由程序主动创建并管理而在 IoC 中对象的创建和生命周期交由 Spring 容器管理程序通过依赖注入获得所需的对象。依赖注入DI 容器负责将需要的依赖如服务类、工具类注入到使用它们的组件中而不需要显式创建这些依赖。 2. Spring 容器的主要实现 Spring 提供了两种核心的 IoC 容器实现 BeanFactory 基础容器提供最基本的 IoC 功能按需加载 Bean延迟初始化。适合资源受限的场景。ApplicationContext 功能更丰富的容器支持事件发布、国际化、Bean 生命周期回调等功能。常用实现包括 ClassPathXmlApplicationContext通过 XML 配置文件加载 Bean。AnnotationConfigApplicationContext通过注解配置加载 Bean。WebApplicationContext专为 Web 应用设计的容器。 3. 使用 Spring 容器动态获取 Bean 通过 Spring 容器获取 Bean 的方式有多种以下重点讲解动态获取的场景 1. 使用 ApplicationContext.getBean 动态获取 Bean ApplicationContext.getBean 方法可以根据名称或类型动态获取 Bean。例如 Autowired private ApplicationContext applicationContext;public void getBeanExample() {// 根据 Bean 名称获取MyService myServiceByName (MyService) applicationContext.getBean(myService);// 根据类型获取MyService myServiceByType applicationContext.getBean(MyService.class);// 根据名称和类型获取MyService myServiceByNameAndType applicationContext.getBean(myService, MyService.class); }2. 使用 Autowired 注入 Autowired 是 Spring 提供的注解用于自动装配依赖。其本质也是通过容器获取对象并注入 Autowired private MyService myService;public void useService() {myService.performTask(); }4. 配置 Spring 容器的方式 1. 基于注解的配置 推荐使用注解方式配置 Spring 容器 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class AppConfig {Beanpublic MyService myService() {return new MyServiceImpl();} }加载 Spring 容器 import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class SpringContainerExample {public static void main(String[] args) {ApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);MyService myService context.getBean(MyService.class);myService.performTask();} }2. 基于 XML 的配置 虽然 XML 配置方式较少使用但仍有必要了解 XML 配置文件applicationContext.xml beans xmlnshttp://www.springframework.org/schema/beans ...bean idmyService classcom.example.MyServiceImpl / /beans加载容器 import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringContainerExample {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);MyService myService (MyService) context.getBean(myService);myService.performTask();} }5. 使用场景中的优化策略 动态场景 动态获取不同的实现类如策略模式中的支付方式。配合 getBean 方法动态注入提高灵活性。 注解优先 使用 Component 标注类Autowired 注入依赖减少配置代码。 多环境支持 结合 Profile 实现多环境配置。 提升性能 结合 Lazy 实现延迟加载优化资源占用。 6. 总结 Spring 容器通过 IoC 和 DI 大幅简化了应用程序中对象的管理和依赖的配置极大提高了开发效率和代码质量。动态获取 Bean、注解配置等功能为复杂业务场景如策略模式提供了便捷的实现方式。 1.策略模式 1.1 业务场景 假设有这样的业务场景大数据系统把文件推送过来根据不同类型的文件采取不同的解析方式。多数的小伙伴就会写出以下的代码 if(typeA){//按照A格式解析 }else if(typeB){//按B格式解析 }else{//按照默认格式解析 }这个代码可能会存在哪些问题呢 如果分支变多这里的代码就会变得臃肿难以维护可读性低。如果你需要接入一种新的解析类型那只能在原有代码上修改。 说得专业一点的话就是以上代码违背了面向对象编程的开闭原则以及单一原则。 开闭原则对于扩展是开放的但是对于修改是封闭的增加或者删除某个逻辑都需要修改到原来代码单一原则规定一个类应该只有一个发生变化的原因修改任何类型的分支逻辑代码都需要改动当前类的代码。 如果你的代码就是酱紫有多个if...else等条件分支并且每个条件分支可以封装起来替换的我们就可以使用策略模式来优化。 1.2 策略模式定义 策略模式定义了算法族分别封装起来让它们之间可以相互替换此模式让算法的变化独立于使用算法的的客户。这个策略模式的定义是不是有点抽象呢那我们来看点通俗易懂的比喻 假设你跟不同性格类型的小姐姐约会要用不同的策略有的请电影比较好有的则去吃小吃效果不错有的去逛街买买买最合适。当然目的都是为了得到小姐姐的芳心请看电影、吃小吃、逛街就是不同的策略。 策略模式针对一组算法将每一个算法封装到具有共同接口的独立的类中从而使得它们可以相互替换。 1.3 策略模式使用 策略模式怎么使用呢酱紫实现的 定义策略接口一个接口或者抽象类里面两个方法一个方法匹配类型一个可替换的逻辑实现方法实现不同的策略不同策略的差异化实现(就是说不同策略的实现类)使用策略模式 1.3.1 定义策略接口一个接口两个方法 public interface IFileStrategy {//属于哪种文件解析类型FileTypeResolveEnum gainFileType();//封装的公用算法具体的解析方法void resolve(Object objectparam); }1.3.2 实现不同的策略 A 类型策略具体实现 Component public class AFileResolve implements IFileStrategy {private static final Logger logger LoggerFactory.getLogger(AFileResolve.class);//1.匹配类型Overridepublic FileTypeResolveEnum gainFileType() {return FileTypeResolveEnum.File_A_RESOLVE;}//2.封装的公用算法具体的解析方法Overridepublic void resolve(Object objectparam) {logger.info(A 类型解析文件参数{},objectparam);//A类型解析具体逻辑} }B 类型策略具体实现 Component public class BFileResolve implements IFileStrategy {private static final Logger logger LoggerFactory.getLogger(BFileResolve.class);Overridepublic FileTypeResolveEnum gainFileType() {return FileTypeResolveEnum.File_B_RESOLVE;}Overridepublic void resolve(Object objectparam) {logger.info(B 类型解析文件参数{},objectparam);//B类型解析具体逻辑} }默认类型策略具体实现 Component public class DefaultFileResolve implements IFileStrategy {private static final Logger logger LoggerFactory.getLogger(DefaultFileResolve.class);Overridepublic FileTypeResolveEnum gainFileType() {return FileTypeResolveEnum.File_DEFAULT_RESOLVE;}Overridepublic void resolve(Object objectparam) {logger.info(默认类型解析文件参数{},objectparam);//默认类型解析具体逻辑} }1.3.3 使用策略模式 如何使用呢我们借助spring的生命周期使用ApplicationContextAware接口把对应的策略初始化到map里面。然后对外提供resolveFile方法即可。 Component public class StrategyUseService implements ApplicationContextAware{private MapFileTypeResolveEnum, IFileStrategy iFileStrategyMap new ConcurrentHashMap();public void resolveFile(FileTypeResolveEnum fileTypeResolveEnum, Object objectParam) {IFileStrategy iFileStrategy iFileStrategyMap.get(fileTypeResolveEnum);if (iFileStrategy ! null) {iFileStrategy.resolve(objectParam);}}//把不同策略放到mapOverridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {MapString, IFileStrategy tmepMap applicationContext.getBeansOfType(IFileStrategy.class);tmepMap.values().forEach(strategyService - iFileStrategyMap.put(strategyService.gainFileType(), strategyService));} }2. 工厂模式 核心 利用 Java多态 进行公共功能同一抽象使用 父类接口 指向 子类对象 进行优化根据不同类型 创建对应子类 3. 简单工厂模式 3.1 模式简介 简单工厂模式是一种创建型设计模式用于通过一个工厂类根据不同的输入参数动态决定实例化哪一个类。它将对象的创建逻辑集中在一个工厂类中从而提高代码的复用性和维护性。 3.2 模式结构 工厂类Factory 负责创建产品对象的逻辑。抽象产品类Product 定义产品的公共接口。具体产品类ConcreteProduct 实现抽象产品接口的具体对象。 3.3 实现步骤 3.3.1 定义产品接口和具体实现 定义一个 Shape 接口所有具体产品实现该接口。 /*** 抽象产品接口*/ public interface Shape {void draw(); }/*** 具体产品圆形*/ public class Circle implements Shape {Overridepublic void draw() {System.out.println(绘制圆形);} }/*** 具体产品矩形*/ public class Rectangle implements Shape {Overridepublic void draw() {System.out.println(绘制矩形);} }/*** 具体产品三角形*/ public class Triangle implements Shape {Overridepublic void draw() {System.out.println(绘制三角形);} }3.3.2 创建工厂类 工厂类包含逻辑根据输入参数返回对应的具体产品实例。 /*** 简单工厂类*/ public class ShapeFactory {public static Shape createShape(String shapeType) {if (circle.equalsIgnoreCase(shapeType)) {return new Circle();} else if (rectangle.equalsIgnoreCase(shapeType)) {return new Rectangle();} else if (triangle.equalsIgnoreCase(shapeType)) {return new Triangle();} else {throw new IllegalArgumentException(未知的图形类型 shapeType);}} }3.3.3 测试简单工厂模式 编写测试类验证简单工厂模式的功能。 public class SimpleFactoryTest {public static void main(String[] args) {// 创建各种图形Shape circle ShapeFactory.createShape(circle);circle.draw();Shape rectangle ShapeFactory.createShape(rectangle);rectangle.draw();Shape triangle ShapeFactory.createShape(triangle);triangle.draw();} }3.3.4 运行结果 运行测试代码后会输出以下内容 绘制圆形 绘制矩形 绘制三角形4.4 优缺点分析 优点 封装性强 工厂类集中管理对象的创建逻辑避免了重复代码。可维护性好 如果需要新增产品类型只需修改工厂类不影响客户端代码。 缺点 违反开闭原则 每次增加新产品都需要修改工厂类。单一职责压力大 工厂类的职责过于集中可能会成为系统的性能瓶颈。 3.5 优化方案 使用 工厂方法模式 可以解决简单工厂模式中违反开闭原则的问题。工厂方法模式通过定义多个具体工厂类每个工厂类负责创建一种产品符合开闭原则。 2.1 业务场景 工厂模式一般配合策略模式一起使用。用来去优化大量的if...else...或switch...case...条件语句。 我们就取第一小节中策略模式那个例子吧。根据不同的文件解析类型创建不同的解析对象 IFileStrategy getFileStrategy(FileTypeResolveEnum fileType){IFileStrategy fileStrategy ;if(fileTypeFileTypeResolveEnum.File_A_RESOLVE){fileStrategy new AFileResolve();}else if(fileTypeFileTypeResolveEnum.File_A_RESOLV){fileStrategy new BFileResolve();}else{fileStrategy new DefaultFileResolve();}return fileStrategy;}其实这就是工厂模式定义一个创建对象的接口让其子类自己决定实例化哪一个工厂类工厂模式使其创建过程延迟到子类进行。 策略模式的例子没有使用上一段代码而是借助spring的特性搞了一个工厂模式哈哈小伙伴们可以回去那个例子细品一下我把代码再搬下来小伙伴们再品一下吧 Component public class StrategyUseService implements ApplicationContextAware{private MapFileTypeResolveEnum, IFileStrategy iFileStrategyMap new ConcurrentHashMap();//把所有的文件类型解析的对象放到map需要使用时信手拈来即可。这就是工厂模式的一种体现啦Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {MapString, IFileStrategy tmepMap applicationContext.getBeansOfType(IFileStrategy.class);tmepMap.values().forEach(strategyService - iFileStrategyMap.put(strategyService.gainFileType(), strategyService));} }2.2 使用工厂模式 定义工厂模式也是比较简单的: 一个工厂接口提供一个创建不同对象的方法。其子类实现工厂接口构造不同对象使用工厂模式 2.3.1 一个工厂接口 interface IFileResolveFactory{void resolve(); }2.3.2 不同子类实现工厂接口 class AFileResolve implements IFileResolveFactory{void resolve(){System.out.println(文件A类型解析);} }class BFileResolve implements IFileResolveFactory{void resolve(){System.out.println(文件B类型解析);} }class DefaultFileResolve implements IFileResolveFactory{void resolve(){System.out.println(默认文件类型解析);} }2.3.3 使用工厂模式 //构造不同的工厂对象 IFileResolveFactory fileResolveFactory; if(fileType“A”){fileResolveFactory new AFileResolve(); }else if(fileType“B”){fileResolveFactory new BFileResolve();}else{fileResolveFactory new DefaultFileResolve(); }fileResolveFactory.resolve();一般情况下对于工厂模式你不会看到以上的代码。工厂模式会跟配合其他设计模式如策略模式一起出现的。 2.4 工厂方法模式 VS 简单工厂模式 特性简单工厂模式工厂方法模式创建逻辑集中性集中在一个工厂类中分散到多个具体工厂类符合开闭原则不符合符合灵活性较低较高类的数量较少较多使用场景产品种类较少且变化较少的场景产品种类较多且变化频繁的场景 3. 责任链模式 3.1 业务场景 我们来看一个常见的业务场景下订单。 下订单接口通常包含以下逻辑 参数非空校验安全校验黑名单校验规则拦截 很多开发者会直接使用异常来实现但这种做法可能存在以下问题 不便扩展异常只能返回异常信息扩展性差。效率低下用异常做逻辑判断效率低。 解决方式使用责任链模式。 以下是传统异常实现的代码示例 public class Order {public void checkNullParam(Object param) {// 参数非空校验throw new RuntimeException();}public void checkSecurity() {// 安全校验throw new RuntimeException();}public void checkBlackList() {// 黑名单校验throw new RuntimeException();}public void checkRule() {// 规则拦截throw new RuntimeException();}public static void main(String[] args) {Order order new Order();try {order.checkNullParam(null); // 参数非空校验order.checkSecurity(); // 安全校验order.checkBlackList(); // 黑名单校验order.checkRule(); // 规则拦截System.out.println(Order success);} catch (RuntimeException e) {System.out.println(Order fail);}} }上述代码的问题包括 使用异常进行逻辑判断效率低且难以扩展。异常设计初衷是处理意外情况过度使用违背了设计原则。 这段代码使用了异常来做逻辑条件判断如果后续逻辑越来越复杂的话会出现一些问题如异常只能返回异常信息不能返回更多的字段这时候需要自定义异常类。 【强制】 异常不要用来做流程控制条件控制。说明异常设计的初衷是解决程序运行中的各种意外情况且异常的处理效率比条件判断方式要低很多。 阿里开发手册规定禁止用异常做逻辑判断。 优化方案责任链模式。 3.2 责任链模式定义 当希望让多个对象有机会处理某个请求时可以使用责任链模式。 定义责任链模式为请求创建一个接收者对象的链每个对象节点根据条件决定是否处理请求或将其传递给下一个节点。这样实现了请求的发送者和接收者的解耦。 责任链模式的核心是将处理逻辑串成链条让请求依次传递。 定义责任链模式为请求创建了一个接收者对象的链。执行链上有多个对象节点每个对象节点都有机会条件匹配处理请求事务如果某个对象节点处理完了就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。这种模式给予请求的类型对请求的发送者和接收者进行解耦。 责任链模式实际上是一种处理请求的模式它让多个处理器对象节点都有机会处理该请求直到其中某个处理成功为止。责任链模式把多个处理器串成链然后让请求在链上传递 打个比喻 假设你晚上去上选修课为了可以走点走坐到了最后一排。来到教室发现前面坐了好几个漂亮的小姐姐于是你找张纸条写上“你好, 可以做我的女朋友吗如果不愿意请向前传”。纸条就一个接一个的传上去了后来传到第一排的那个妹子手上她把纸条交给老师听说老师40多岁未婚… 3.3 责任链模式使用 核心步骤 定义一个接口或抽象类。每个责任节点实现接口或继承抽象类进行差异化处理。初始化责任链将节点串联起来。 3.3.1 一个接口或者抽象类 这个接口或者抽象类需要 有一个指向责任下一个对象的属性一个设置下一个对象的set方法给子类对象差异化实现的方法如以下代码的doFilter方法 抽象类包含 指向下一个处理节点的引用。设置下一个处理节点的方法。子类实现的处理逻辑方法。 public abstract class AbstractHandler {//责任链中的下一个对象private AbstractHandler nextHandler;/*** 责任链的下一个对象*/public void setNextHandler(AbstractHandler nextHandler){this.nextHandler nextHandler;}/*** 具体参数拦截逻辑,给子类去实现*/public void filter(Request request, Response response) {doFilter(request, response);if (getNextHandler() ! null) {getNextHandler().filter(request, response);}}public AbstractHandler getNextHandler() {return nextHandler;}abstract void doFilter(Request filterRequest, Response response);}3.3.2 每个对象差异化处理 责任链上每个对象的差异化处理如本小节的业务场景就有参数校验对象、安全校验对象、黑名单校验对象、规则拦截对象 /*** 参数校验对象**/ Component Order(1) //顺序排第1最先校验 public class CheckParamFilterObject extends AbstractHandler {Overridepublic void doFilter(Request request, Response response) {System.out.println(非空参数检查);} }/*** 安全校验对象*/ Component Order(2) //校验顺序排第2 public class CheckSecurityFilterObject extends AbstractHandler {Overridepublic void doFilter(Request request, Response response) {//invoke Security checkSystem.out.println(安全调用校验);} } /*** 黑名单校验对象*/ Component Order(3) //校验顺序排第3 public class CheckBlackFilterObject extends AbstractHandler {Overridepublic void doFilter(Request request, Response response) {//invoke black list checkSystem.out.println(校验黑名单);} }/*** 规则拦截对象*/ Component Order(4) //校验顺序排第4 public class CheckRuleFilterObject extends AbstractHandler {Overridepublic void doFilter(Request request, Response response) {System.out.println(规则校验);} }3.3.3 对象链连起来初始化 使用 使用Spring的依赖注入将责任节点串联起来。 Component(ChainPatternDemo) public class ChainPatternDemo {//自动注入各个责任链的对象Autowiredprivate ListAbstractHandler abstractHandleList;private AbstractHandler abstractHandler;//spring注入后自动执行责任链的对象连接起来PostConstructpublic void initializeChainFilter(){for(int i 0;iabstractHandleList.size();i){if(i 0){abstractHandler abstractHandleList.get(0);}else{AbstractHandler currentHander abstractHandleList.get(i - 1);AbstractHandler nextHander abstractHandleList.get(i);currentHander.setNextHandler(nextHander);}}}//直接调用这个方法使用public Response exec(Request request, Response response) {abstractHandler.filter(request, response);return response;}public AbstractHandler getAbstractHandler() {return abstractHandler;}public void setAbstractHandler(AbstractHandler abstractHandler) {this.abstractHandler abstractHandler;} }运行结果 执行代码后输出 非空参数检查 安全调用校验 校验黑名单 规则校验4. 模板方法模式 核心思想 通过抽象类定义业务流程骨架子类根据具体需求实现差异化代码。约束子类的业务执行流程保证流程的一致性和规范性。 实现步骤 定义模板方法的抽象类包含固定流程的定义。实现具体步骤由子类实现差异化逻辑。使用模板方法调用统一的处理逻辑。 4.1 业务场景 假设一个内部系统需要处理不同商户的请求与外部第三方系统进行 HTTP 通信。每个请求需要经过以下固定流程 每个请求需要经过以下固定流程 查询商户信息。对请求报文加签。发送 HTTP 请求。对返回的报文验签。 此外不同商户可能采用不同的通信方式 商户 A 通过代理通信。商户 B 直接连接。 原始实现问题 以 A 商户和 B 商户为例原始实现如下 // 商户 A 处理逻辑 class CompanyAHandler implements RequestHandler {public Resp handle(Req req) {//查询商户信息queryMerchantInfo();//加签signature();//http请求A商户假设走的是代理httpRequestbyProxy()//验签verify();return new Resp();} }// 商户 B 处理逻辑 class CompanyBHandler implements RequestHandler {public Resp handle(Req req) {//查询商户信息queryMerchantInfo();//加签signature();// http请求B商户不走代理直连httpRequestbyDirect();// 验签verify(); return new Resp();} }缺点 代码重复通用流程在多个子类中重复实现。难以扩展新增商户需要完整实现所有逻辑。 为了解决这些问题可以使用模板方法模式。 4.2 模板方法模式定义 模板方法模式 定义一个操作中的算法的骨架流程把一些步骤的具体实现留给子类。子类可以在不改变算法结构的前提下重定义某些步骤。 核心思想定义一个操作的一系列步骤对于某些暂时确定不下来的步骤就留给子类去实现这样不同的子类就可以定义出不同的步骤。 通俗比喻 模板方法模式 举例追女朋友需要按顺序完成牵手 → 拥抱 → 接吻 → 拍拍手。具体用左手还是右手牵这种细节交给实现者决定但整体流程固定。 4.3 模板方法使用 一个抽象类定义骨架流程抽象方法放一起确定的共同方法步骤放到抽象类去除抽象方法标记不确定的步骤给子类去差异化实现 我们继续那以上的举例的业务流程例子来一起用 模板方法优化一下哈 4.3.1 定义抽象类 抽象类定义通用业务流程骨架 /*** 抽象类定义业务流程骨架*/ abstract class AbstractMerchantService {// 1.查询商户信息abstract void queryMerchantInfo();// 2.加签abstract void signature();// 3.发送 HTTP 请求abstract void httpRequest();// 4.验签abstract void verifySignature();// 5.Http是否走代理提供给子类实现abstract boolean isRequestByProxy();/*** 模板方法定义处理请求的流程*/public Resp handleTemplate(Req req) {queryMerchantInfo();signature();httpRequest();verifySignature();return new Resp();} }4.3.2 子类实现差异化逻辑 商户 A 的实现 /*** 商户 A 实现类*/ class CompanyAServiceImpl extends AbstractMerchantService {Overridevoid queryMerchantInfo() {System.out.println(查询商户 A 信息);}Overridevoid signature() {System.out.println(对商户 A 请求报文加签);}Overridevoid httpRequest() {System.out.println(通过代理发送商户 A 的 HTTP 请求);}Overridevoid verifySignature() {System.out.println(验证商户 A 返回报文签名);}// 公司 A 走 http代理Overrideboolean isRequestByProxy(){return true;} }商户 B 的实现 /*** 商户 B 实现类*/ class CompanyBServiceImpl extends AbstractMerchantService {Overridevoid queryMerchantInfo() {System.out.println(查询商户 B 信息);}Overridevoid signature() {System.out.println(对商户 B 请求报文加签);}Overridevoid httpRequest() {System.out.println(通过直连发送商户 B 的 HTTP 请求);}Overridevoid verifySignature() {System.out.println(验证商户 B 返回报文签名);}// 公司 B 不走 http代理Overrideboolean isRequestByProxy(){return false;} }4.3.3. 使用模板方法 调用模板方法处理请求 public class Main {public static void main(String[] args) {AbstractMerchantService serviceA new CompanyAServiceImpl();AbstractMerchantService serviceB new CompanyBServiceImpl();// 处理商户 A 请求Resp respA serviceA.handleTemplate(new Req());System.out.println(商户 A 请求处理完成);// 处理商户 B 请求Resp respB serviceB.handleTemplate(new Req());System.out.println(商户 B 请求处理完成);} }5. 观察者模式监听模式 5.1 业务场景 登陆注册应该是最常见的业务场景了。就拿注册来说我们经常会遇到类似的场景用户注册成功后需要给用户发送一条消息、邮件或者其他通知。通常代码如下 void register(User user){insertRegisterUser(user);sendIMMessage();sendEmail() }这段代码存在的问题是 违反开闭原则如果产品新增需求例如注册成功后再给用户发送短信通知就需要修改 register 方法的代码。 void register(User user){insertRegisterUser(user);sendIMMessage();sendMobileMessage();sendEmail() }同步阻塞问题如果调用“发送短信”的接口失败可能会影响用户注册流程。 为了解决这些问题可以使用观察者模式进行优化。 5.2 观察者模式定义 观察者模式定义对象之间的一对多依赖关系使得一个对象的状态发生改变时所有依赖它的对象都会收到通知并自动更新。 观察者模式属于行为型模式。一个对象被观察者的状态发生改变时会通知所有依赖对象观察者。 核心成员 被观察者Observerable目标对象状态发生变化时通知所有观察者。观察者Observer依赖被观察者并响应其状态变化。 使用场景 事件异步通知例如用户注册成功后发送消息、邮件等操作。 5.3 观察者模式使用 观察者模式实现的话还是比较简单的。 一个被观察者的类Observerable ;多个观察者Observer 观察者的差异化实现经典观察者模式封装EventBus实战 5.3.1 被观察者类 Observerable import java.util.List; import java.util.concurrent.CopyOnWriteArrayList;// 被观察者 public class Observerable {// 使用线程安全的Listprivate final ListObserver observers new CopyOnWriteArrayList();// 定义状态常量public static final int STATE_NOTIFY 1;private int state;public int getState() {return state;}// 设置状态并通知观察者public void setState(int state) {this.state state;notifyAllObservers();}// 添加观察者public void addObserver(Observer observer) {observers.add(observer);}// 移除观察者public void removeObserver(Observer observer) {observers.remove(observer);}// 通知所有观察者private void notifyAllObservers() {if (state ! STATE_NOTIFY) {System.out.println(状态非通知状态不触发通知。);return;}observers.forEach(Observer::doEvent);} }5.3.2 观察者接口 Observer 及其实现类 // 观察者接口 public interface Observer {void doEvent(); }// IM 消息观察者 public class IMMessageObserver implements Observer {Overridepublic void doEvent() {System.out.println(发送 IM 消息);} }// 短信观察者 public class MobileNoObserver implements Observer {Overridepublic void doEvent() {System.out.println(发送短信消息);} }// 邮件观察者 public class EmailObserver implements Observer {Overridepublic void doEvent() {System.out.println(发送邮件消息);} } 5.3.3 测试代码 public class ObserverPatternDemo {public static void main(String[] args) {Observerable observerable new Observerable();// 添加观察者observerable.addObserver(new IMMessageObserver());observerable.addObserver(new MobileNoObserver());observerable.addObserver(new EmailObserver());// 设置状态并触发通知observerable.setState(Observerable.STATE_NOTIFY);} }5.3.4 使用 Guava EventBus 实现的观察者模式优化 直接实现观察者模式会略显繁琐Google 提供的 Guava EventBus 封装了一套基于注解的事件总线使用起来更加简单方便。 EventBus 中心类 import com.google.common.eventbus.EventBus;public class EventBusCenter {private static final EventBus EVENT_BUS new EventBus();private EventBusCenter() {// 禁止实例化}public static EventBus getInstance() {return EVENT_BUS;}//添加观察者public static void register(Object obj) {EVENT_BUS.register(obj);}//移除观察者public static void unregister(Object obj) {EVENT_BUS.unregister(obj);}//把消息推给观察者public static void post(Object obj) {EVENT_BUS.post(obj);} }观察者类 EventListener import com.google.common.eventbus.Subscribe;public class EventListener {Subscribe //加了订阅这里标记这个方法是事件处理方法 public void handle(NotifyEvent notifyEvent) {System.out.println(发送 IM 消息 notifyEvent.getImNo());System.out.println(发送短信消息 notifyEvent.getMobileNo());System.out.println(发送邮件消息 notifyEvent.getEmailNo());} }通知事件类 NotifyEvent //通知事件类 public class NotifyEvent {private final String mobileNo;private final String emailNo;private final String imNo;public NotifyEvent(String mobileNo, String emailNo, String imNo) {this.mobileNo mobileNo;this.emailNo emailNo;this.imNo imNo;}public String getMobileNo() {return mobileNo;}public String getEmailNo() {return emailNo;}public String getImNo() {return imNo;} }测试代码 public class EventBusDemoTest {public static void main(String[] args) {EventListener eventListener new EventListener();EventBusCenter.register(eventListener);EventBusCenter.post(new NotifyEvent(13372817283, 123qq.com, 666));} } public class EventBusDemoTest {public static void main(String[] args) {// 注册观察者EventListener eventListener new EventListener();EventBusCenter.register(eventListener);// 发布通知事件NotifyEvent event new NotifyEvent(13372817283, 123qq.com, 666);EventBusCenter.post(event);} }输出结果 发送IM消息: 666 发送短信消息: 13372817283 发送Email消息: 123qq.com6. 单例模式 6.1 业务场景 单例模式保证一个类仅有一个实例并提供一个访问它的全局访问点。I/O与数据库的连接,一般就用单例模式实现de的。Windows里面的Task Manager任务管理器也是很典型的单例模式。 来看一个单例模式的例子 public class LanHanSingleton {private static LanHanSingleton instance;private LanHanSingleton(){}public static LanHanSingleton getInstance(){if (instance null) {instance new LanHanSingleton();}return instance;}}以上的例子就是懒汉式的单例实现。实例在需要用到的时候才去创建就比较懒。如果有则返回没有则新建需要加下 synchronized关键字要不然可能存在线性安全问题。 6.2 单例模式的经典写法 其实单例模式还有有好几种实现方式如饿汉模式双重校验锁静态内部类枚举等实现方式。 6.2.1 饿汉模式 public class EHanSingleton {private static EHanSingleton instance new EHanSingleton();private EHanSingleton(){ }public static EHanSingleton getInstance() {return instance;}}饿汉模式它比较饥饿、比较勤奋实例在初始化的时候就已经建好了不管你后面有没有用到都先新建好实例再说。这个就没有线程安全的问题但是呢浪费内存空间呀。 6.2.2 双重校验锁 public class DoubleCheckSingleton {private volatile static DoubleCheckSingleton instance;private DoubleCheckSingleton() { }public static DoubleCheckSingleton getInstance(){if (instance null) {synchronized (DoubleCheckSingleton.class) {if (instance null) {instance new DoubleCheckSingleton();}}}return instance;} }双重校验锁实现的单例模式综合了懒汉式和饿汉式两者的优缺点。以上代码例子中在synchronized关键字内外都加了一层 if条件判断这样既保证了线程安全又比直接上锁提高了执行效率还节省了内存空间。 6.2.3 静态内部类 public class InnerClassSingleton {private static class InnerClassSingletonHolder{private static final InnerClassSingleton INSTANCE new InnerClassSingleton();}private InnerClassSingleton(){}public static final InnerClassSingleton getInstance(){return InnerClassSingletonHolder.INSTANCE;} }静态内部类的实现方式效果有点类似双重校验锁。但这种方式只适用于静态域场景双重校验锁方式可在实例域需要延迟初始化时使用。 6.2.4 枚举 public enum SingletonEnum {INSTANCE;public SingletonEnum getInstance(){return INSTANCE;} }枚举实现的单例代码简洁清晰。并且它还自动支持序列化机制绝对防止多次实例化。 7.代理模式 代理模式Proxy Pattern 是一种结构型设计模式通过为其他对象提供一种代理以控制对这个对象的访问。代理对象作为实际对象的代表负责处理客户端与实际对象之间的交互。 7.1 模式简介 代理模式为实际对象提供了一个替代方案或占位符可以在不改变实际对象的情况下增强功能、控制访问或延迟加载。常见的代理模式包括 静态代理动态代理 JDK 动态代理CGLIB 动态代理 7.2 模式结构 代理模式包含以下主要角色 抽象主题Subject 定义实际对象和代理对象的公共接口。实际对象RealSubject 实现抽象主题接口的具体类包含实际业务逻辑。代理对象Proxy 通过实现抽象主题接口来代理实际对象可以在调用实际对象方法时执行额外操作。 7.3 实现步骤 示例场景用户服务的代理 假设有一个 UserService 接口提供用户登录功能。我们使用代理模式来扩展日志记录功能。 7.3.1 静态代理实现 Step 1: 定义抽象主题和实际对象 定义 UserService 接口和实现类 /*** 抽象主题用户服务接口*/ public interface UserService {void login(String username, String password); }/*** 实际对象用户服务实现类*/ public class UserServiceImpl implements UserService {Overridepublic void login(String username, String password) {System.out.println(username 登录成功);} }Step 2: 创建代理对象 代理对象实现与实际对象相同的接口并在调用实际对象方法时添加额外功能 /*** 静态代理类用户服务代理*/ public class UserServiceProxy implements UserService {private final UserService userService;// 通过构造函数传入实际对象public UserServiceProxy(UserService userService) {this.userService userService;}Overridepublic void login(String username, String password) {// 添加额外功能日志记录System.out.println(日志记录用户 username 尝试登录。);// 调用实际对象的方法userService.login(username, password);System.out.println(日志记录用户 username 登录操作完成。);} }Step 3: 测试静态代理 测试代理功能 public class StaticProxyTest {public static void main(String[] args) {// 创建实际对象UserService userService new UserServiceImpl();// 创建代理对象UserService proxy new UserServiceProxy(userService);// 使用代理对象proxy.login(Alice, 123456);} }运行结果 日志记录用户 Alice 尝试登录。 Alice 登录成功 日志记录用户 Alice 登录操作完成。7.3.2 动态代理实现 动态代理 是在运行时动态生成代理类无需手动为每个类编写代理代码。 JDK 动态代理 Step 1: 使用 InvocationHandler 接口 动态代理使用 InvocationHandler 处理方法调用 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;public class LoggingInvocationHandler implements InvocationHandler {private final Object target;// 构造函数接受实际对象public LoggingInvocationHandler(Object target) {this.target target;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 前置增强日志记录System.out.println(日志记录方法 method.getName() 开始执行。);// 调用实际对象的方法Object result method.invoke(target, args);// 后置增强日志记录System.out.println(日志记录方法 method.getName() 执行完成。);return result;} }Step 2: 生成动态代理类 通过 Proxy.newProxyInstance 方法生成代理对象 import java.lang.reflect.Proxy;public class DynamicProxyTest {public static void main(String[] args) {// 创建实际对象UserService userService new UserServiceImpl();// 创建动态代理对象UserService proxy (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),new LoggingInvocationHandler(userService));// 使用代理对象proxy.login(Bob, 654321);} }运行结果 日志记录方法 login 开始执行。 Bob 登录成功 日志记录方法 login 执行完成。CGLIB 动态代理 CGLIB 动态代理 使用字节码生成技术可以代理没有实现接口的类。 依赖 添加 cglib 和 asm 依赖 dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.3.0/version /dependency实现 import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** CGLIB 动态代理*/ public class CglibProxy implements MethodInterceptor {private final Object target;public CglibProxy(Object target) {this.target target;}public Object getProxyInstance() {Enhancer enhancer new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(this);return enhancer.create();}Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(日志记录方法 method.getName() 开始执行。);Object result proxy.invokeSuper(obj, args);System.out.println(日志记录方法 method.getName() 执行完成。);return result;} }测试 public class CglibProxyTest {public static void main(String[] args) {// 创建实际对象UserServiceImpl userService new UserServiceImpl();// 创建代理对象CglibProxy proxy new CglibProxy(userService);UserServiceImpl proxyInstance (UserServiceImpl) proxy.getProxyInstance();// 使用代理对象proxyInstance.login(Charlie, 112233);} }7.4 优缺点分析 优点 增强功能 通过代理对象添加额外功能如日志、权限检查等。解耦合 客户端与实际对象之间的交互通过代理对象实现便于维护。灵活性 动态代理可在运行时动态生成代理对象无需手动编写代理类。 缺点 性能开销 动态代理涉及反射调用性能略低于静态代理。复杂性增加 对新手开发者来说动态代理的学习曲线较陡。
http://www.dnsts.com.cn/news/113408.html

相关文章:

  • 辽源网站建设开发公司资质哪里查
  • 我的网站360搜索被做跳转魔艺极速建站
  • 湖南信息网官方网站郑州购物网站建设
  • 临沂做商城网站的公司网站 改版 建议
  • 网站上的彩票走势图是怎么做的企业seo网站营销推广
  • 网站开发方式演进网站设计要如何做支付功能
  • 网站html源码西安网站维护
  • 平面网站设计全网营销公司排名前十
  • 网站怎么屏蔽ip访问搞笑网站模板
  • 百度百科查询网站改版对seo
  • php网站服务器架设电子贺卡制作模板
  • 汉字域名的网站有哪些杨凌开发建设局网站
  • dw怎样建设网站建设网站宣传页
  • 做淘客网站企业备案wordpress小论坛
  • 网站标题优化 英文提供企业网站建设方案
  • 在网站和网页的区别网店运营计划书范文
  • 企业网站开发职责模板建站服务器
  • 佛山外贸网站建设机构做有关兼职网站的需求分析
  • 通桥小学的网站建设网站支付宝网上支付功能怎么做
  • 建设通网站账号一流本科专业建设网站
  • 关于做网站的英语对话wordpress外贸数码
  • 酒泉建设厅网站总结企业网站建设的流程
  • 自助建网站的平台 数据库邢台网站建设网站
  • wordpress2016深圳seo网络公司
  • 天城建设网站自己做公司网站需要什么
  • 网站域名去哪买网站建设步和客户沟通
  • 大城网站制作怎么做网站推销产品
  • 山药云搭建网站做网站用虚拟主机好吗
  • 昆明seo网站建设费用软件开发工程师需要什么证书
  • 网站如何收录wordpress页头登录