重新拜读一边《XX程序设计》后,发现程序设计是一个很有意思的东西,不得不说, 单纯的堆砌代码去实现功能是可取,但不太长久,主要代码取决于想法,只要懂逻辑,懂语法,我们都能编写出可运行的代码,但质量,重构可能,却取决于开始设计,开始可能觉得没什么,但当项目足够庞大,你就会发现程序设计是多么重要。
对于平常的代码,总会在各种业务下需要修正合并,提取,这应该是很正常的事情(如果没有,当我没说),提取的时候,怎么样让它更好的适应更多类似的问题,适应情况,就是一个设计问题,应该说,其实当你想到这些的时候,你已经算得上开始考虑设计代码了,其实设计模式并不是那么遥远,其实也很近。
主要涉及如下几种模式:(对于UML不太熟悉的可以自行搜索了解,本文首次属于初次记录,后续回看时根据理解程序再补充理解及相应代码)
目录
先来谈谈策略模式 :
再说说访问者模式(双重分派):
回顾装饰模式:
常见的适配器模式:
标准描述:定义算法并将算法一个个封装,并让它们可以相互替换。使得算法可以脱离于使用者而变化
【让实现与操作接口达成松耦合关系,同时满足开-闭原则】
eg:
比如我们需要一个算工钱的方法,但是不同工种需要不同的算法,那我们可以这样来设计:这个算工钱呢是必须要执行的,但是根据不同工种,又不一样的算法,我们仅需要算钱,方法根据工种提供。
这样,我们只需要根据不同人调用不同的工资算法,就可以利用这些已经落实好的方法了。专注于对付不一样的算法,顶层依旧只是根据不一样的情况随时调用即可。
在我们的日常的开发过程中,也很经常遇到这类问题,比如同样的调用一个笼统接口现交由不同人去处理,仅需要调用相应的实现即可,无需重新修改父类导致代码变化(也就是通常的继承方式存在的问题所在)
适应情景:一个类定义了一个笼统的行为,在类中存在多种根据不同条件不同的实现的情况,可以避免大量的条件语句使用。否则上述可能会变成,传入特定参数,跳转不同的方法的判断条件,数量足够多的的时候,就会变得难以维护且臃肿不堪。
策略模式的结构:
①策略:基本上为一个接口,用于定义抽象的方法(类似上方 Salayr.class)
②上下文:为依赖于策略(①)接口的类,内部含有策略声明的变量,也就是对象(正如 DivideMoney.class 中含有salary)。同时存在方法,用于调用具体策略实现所声明的接口方法。(如DivedeMoney中的getSalar方法一致无二)
③具体策略:为策略接口的声明方法的具体实现方法
标准描述:表示一个作用于某对象结构中的各个元素的操作。使得用户可以在不改变各个元素的前提下,定义作用于这些元素的新操作。
eg:
这里引入电费计算方法来说明访问者模式,也是一个典例。
电表是固定的元素,消耗多少实际决定,而费用是根据用电类型来决定,根据不同类型分为工业与居民用电,同时价格计算方式也不一致,但是同样的也需要查看电表才能得出电费的这样一种场景。
访问者模式的结构:
①抽象访问者:一个接口,定义了操作具体元素的方法(如类图中的Visitor.class)
某个类可能用自己的实例方法来操作自己的数据,但是可能存在需要额外的方法来根据自己的数据做新处理,而这种方法不需要自己来实现的情况(就出现了,让一个访问者来查看电表,并根据访问者的方式来计算电费的情况发生)
②抽象元素:一个抽象类,定义了接收访问者的操作(如类图中AmmeterElement.class,定义了3种方法)
在电费这个例子中,存在允许访问者查看电表的方法,同时也需要展示电量等操作,所以电表需要一些方法来让访问的查电表人员了解电表的内容,
③具体访问者:实现接口的类(正如上图HomeAmmeterVistor.class与IndustryAmmeterVistor.class)
相当于查电表的人员,根据不同类型的用电,不同类型的工作人员存在不一样的计费标准
④具体元素:抽象元素的子类(图中Ammeter.class)
具体到某一个电表的因素
双重分派:
这个概念也算是重新看书获得的旧概念了,书本还是可以的。
在上述过程中,被访问者(Ammeter)首先调用accept接收访问者(visitor),被访问者再调用visit访问被访问对象,这个过程被称为 双重分派 ,核心点:数据的存储和操作解耦合。
适应场景:需要对集合中的对象进行很多不同操作且不相关的操作时,又不想改变对象的类时,可以使用访问者模式,在访问者中定义对于集合中对象的操作。
标准描述:动态地给对象添加一些额外的职责,相对继承而言,灵活一些
与传统的继承比较,多了一个中间抽象装饰,有利于解耦继承带来的不便,后续只需要增加具体实现,即可增强对象的功能。只需要根据需要调用具体装饰即可,无需增加过多的子类。关键是可插拔性强。
装饰者模式结构:
①抽象组件:定义了需要装饰的方法,是被装饰的对象 (如上图Car.class)
动态拓展对象功能,而不需要修改原始类代码
②具体组件:指抽象组件的一个子类(对应上方BenChiCar.class)
③装饰:同样是抽象组件子类,但其需要提供额外的方法,用于装饰抽象组件,基于可插拔性,故一般为抽象类(如上方newCar方法,就是为了下方修饰作用)
④具体装饰:负责实现修饰抽象组件(如上方增强了getPrince方法)
适用场景:继承方式不利于维护的情况,动态增强对象功能而又不影响其他部分功能的情况下。
标准描述:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得由于本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式是在日常开发中最容易碰到的,我们根据不同的需求,需要去让框架的内容符合我们的预期结果,而做出的修改。
回归到日常所接触的springMvc,在springboot 内,我们需要配置自己的设置时,官方就提供了WebMvcConfigurerAdapter来扩展功能。可以通过重写接口来支持MVC配置,很明显,这就是我要说的 说明文档传送点:29.1.1提及了
我们主要在这里处理序列化问题,提供FastJson的转换及处理允许的跨域请求(具体跨域请求说明文章)
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List> converters) {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
converters.add(converter);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.exposedHeaders(HttpHeaders.SET_COOKIE)
.maxAge(3600L);
}
}
这样就能根据我们的需要,让spring按照我们的方式处理请求内容。
适配者模式结构:
①目标:目标是一个接口,是客户想使用的接口(如WebMvcConfigurer.class)
②被适配者:为一个存在的接口或抽象类,这个类需要被适配(WebMvcConfigurerAdapter.class)
③适配器:实现了目标接口并包含有被适配者的引用,其职责是对被适配者接口(抽象类)与目标接口对接适配(WebMvcConfigurer.class)
适合场景:针对一些功能我们并不需要交由自己完全实现,需要根据不同条件让客户自己按需修改,说白了,是对抽象类及接口的一种按需插拔的灵活使用方式。