旅游网站功能模块,湛江市建设交易中心网站,企业网站怎样做外链方法,二极管 东莞网站建设文章目录 前言一、策略模式1.1、 业务场景1.2 、策略模式定义1.3、 策略模式使用1.3.1、一个接口#xff0c;两个方法1.3.2、不同策略的差异化实现1.3.3、使用策略模式 二、责任链模式2.1、业务场景2.2、责任链模式定义2.3、责任链模式使用2.3.1、一个接口或者抽象类2.3.2、每… 文章目录 前言一、策略模式1.1、 业务场景1.2 、策略模式定义1.3、 策略模式使用1.3.1、一个接口两个方法1.3.2、不同策略的差异化实现1.3.3、使用策略模式 二、责任链模式2.1、业务场景2.2、责任链模式定义2.3、责任链模式使用2.3.1、一个接口或者抽象类2.3.2、每个对象差异化处理2.3.3、对象链连起来初始化 使用 三、模板方法模式3.1、业务场景3.2、模板方法模式定义3.3、模板方法使用3.3.1、一个抽象类定义骨架流程3.3.2、确定的共同方法步骤放到抽象类3.3.3、不确定的步骤给子类去差异化实现 四、观察者模式4.1、业务场景4.2、观察者模式定义4.3、观察者模式使用4.3.1、一个被观察者的类Observerable 和 多个观察者Observer4.3.2、观察者的差异化实现4.3.3、EventBus实战 五、工厂模式5.1、业务场景5.2、使用工厂模式5.2.1、一个工厂接口5.2.2、不同子类实现工厂接口5.2.3、使用工厂模式 六、单例模式6.1、业务场景6.2、单例模式的经典写法6.2.1、饿汉模式6.2.2、双重校验锁6.2.3、静态内部类6.2.4、枚举 前言
平时我们写代码呢多数情况都是流水线式写代码基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢我觉得最好的方式就是使用设计模式优化自己的业务代码。 一、策略模式
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 {Overridepublic FileTypeResolveEnum gainFileType() {return FileTypeResolveEnum.File_A_RESOLVE;}Overridepublic void resolve(Object objectparam) {logger.info(A 类型解析文件参数{},objectparam);//A类型解析具体逻辑}
}B 类型策略具体实现
Component
public class BFileResolve implements IFileStrategy {Overridepublic FileTypeResolveEnum gainFileType() {return FileTypeResolveEnum.File_B_RESOLVE;}Overridepublic void resolve(Object objectparam) {logger.info(B 类型解析文件参数{},objectparam);//B类型解析具体逻辑}
}默认类型策略具体实现
Component
public class DefaultFileResolve implements IFileStrategy {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.1、业务场景
我们来看一个常见的业务场景下订单。下订单接口基本的逻辑一般有参数非空校验、安全校验、黑名单校验、规则拦截等等。很多伙伴会使用异常来实现
public class Order {public void checkNullParam(Object param){//参数非空校验throw new RuntimeException();}public void checkSecurity(){//安全校验throw new RuntimeException();}public void checkBackList(){//黑名单校验throw new RuntimeException();}public void checkRule(){//规则拦截throw new RuntimeException();}public static void main(String[] args) {Order order new Order();try{order.checkNullParam();order.checkSecurity ();order.checkBackList();order2.checkRule();System.out.println(order success);}catch (RuntimeException e){System.out.println(order fail);}}
}这段代码使用了异常来做逻辑条件判断如果后续逻辑越来越复杂的话会出现一些问题如异常只能返回异常信息不能返回更多的字段这时候需要自定义异常类。
并且阿里开发手册规定禁止用异常做逻辑判断。
【强制】 异常不要用来做流程控制条件控制。说明异常设计的初衷是解决程序运行中的各种意外情况且异常的处理效率比条件判断方式要低很多。
如何优化这段代码呢可以考虑责任链模式
2.2、责任链模式定义
当你想要让一个以上的对象有机会能够处理某个请求的时候就使用责任链模式。
责任链模式为请求创建了一个接收者对象的链。执行链上有多个对象节点每个对象节点都有机会条件匹配处理请求事务如果某个对象节点处理完了就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。这种模式给予请求的类型对请求的发送者和接收者进行解耦。
责任链模式实际上是一种处理请求的模式它让多个处理器对象节点都有机会处理该请求直到其中某个处理成功为止。责任链模式把多个处理器串成链然后让请求在链上传递 2.3、责任链模式使用
责任链模式怎么使用呢
一个接口或者抽象类每个对象差异化处理对象链数组初始化连起来
2.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);}2.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) {//check ruleSystem.out.println(check rule);}
}2.3.3、对象链连起来初始化 使用
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;}
}运行结果如下
非空参数检查
安全调用校验
校验黑名单
check rule三、模板方法模式
3.1、业务场景
假设我们有这么一个业务场景内部系统不同商户调用我们系统接口去跟外部第三方系统交互http方式。走类似这么一个流程如下 一个请求都会经历这几个流程
查询商户信息对请求报文加签发送http请求出去对返回的报文验签
这里有的商户可能是走代理出去的有的是走直连。假设当前有AB商户接入不少伙伴可能这么实现伪代码如下 // 商户A处理句柄
CompanyAHandler implements RequestHandler {Resp hander(req){//查询商户信息queryMerchantInfo();//加签signature();//http请求A商户假设走的是代理httpRequestbyProxy()//验签verify();}
}
// 商户B处理句柄
CompanyBHandler implements RequestHandler {Resp hander(Rreq){//查询商户信息queryMerchantInfo();//加签signature();// http请求B商户不走代理直连httpRequestbyDirect();// 验签verify(); }
}
假设新加一个C商户接入你需要再实现一套这样的代码。显然这样代码就重复了一些通用的方法却在每一个子类都重新写了这一方法。
如何优化呢可以使用模板方法模式。
3.2、模板方法模式定义
定义一个操作中的算法的骨架流程而将一些步骤延迟到子类中使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。它的核心思想就是定义一个操作的一系列步骤对于某些暂时确定不下来的步骤就留给子类去实现这样不同的子类就可以定义出不同的步骤。
3.3、模板方法使用
一个抽象类定义骨架流程抽象方法放一起确定的共同方法步骤放到抽象类去除抽象方法标记不确定的步骤给子类去差异化实现
我们继续那以上的举例的业务流程例子来一起用 模板方法优化一下哈
3.3.1、一个抽象类定义骨架流程
因为一个个请求经过的流程为一下步骤
查询商户信息对请求报文加签发送http请求出去对返回的报文验签
所以我们就可以定义一个抽象类包含请求流程的几个方法方法首先都定义为抽象方法哈
/*** 抽象类定义骨架流程查询商户信息加签http请求验签*/
abstract class AbstractMerchantService { //查询商户信息abstract queryMerchantInfo();//加签abstract signature();//http 请求abstract httpRequest();// 验签abstract verifySinature();}
3.3.2、确定的共同方法步骤放到抽象类
abstract class AbstractMerchantService { //模板方法流程Resp handlerTempPlate(req){//查询商户信息queryMerchantInfo();//加签signature();//http 请求httpRequest();// 验签verifySinature();}// Http是否走代理提供给子类实现abstract boolean isRequestByProxy();
}
3.3.3、不确定的步骤给子类去差异化实现
因为是否走代理流程是不确定的所以给子类去实现。
商户A的请求实现 CompanyAServiceImpl extends AbstractMerchantService{Resp hander(req){return handlerTempPlate(req);}//走http代理的boolean isRequestByProxy(){return true;}
商户B的请求实现 CompanyBServiceImpl extends AbstractMerchantService{Resp hander(req){return handlerTempPlate(req);}//公司B是不走代理的boolean isRequestByProxy(){return false;}四、观察者模式
4.1、业务场景
登陆注册应该是最常见的业务场景了。就拿注册来说事我们经常会遇到类似的场景就是用户注册成功后我们给用户发一条消息又或者发个邮件等等因此经常有如下的代码
void register(User user){insertRegisterUseruser;sendIMMessage();sendEmail()
}这块代码会有什么问题呢如果产品又加需求现在注册成功的用户再给用户发一条短信通知。于是你又得改register方法的代码了。。。这是不是违反了开闭原则啦。
void register(User user){insertRegisterUseruser;sendIMMessage();sendMobileMessage;sendEmail()
}并且如果调发短信的接口失败了是不是又影响到用户注册了这时候是不是得加个异步方法给通知消息才好。。。
实际上我们可以使用观察者模式优化。
4.2、观察者模式定义
观察者模式定义对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖于它的对象都得到通知并被完成业务的更新。
观察者模式属于行为模式一个对象被观察者的状态发生改变所有的依赖对象观察者对象都将得到通知进行广播通知。它的主要成员就是观察者和被观察者。
被观察者Observerable目标对象状态发生变化时将通知所有的观察者。观察者observer接受被观察者的状态变化通知执行预先定义的业务
使用场景 完成某件事情后异步通知场景。如登陆成功发个IM消息等等。
4.3、观察者模式使用
观察者模式实现的话还是比较简单的。
一个被观察者的类Observerable ;多个观察者Observer 观察者的差异化实现经典观察者模式封装EventBus实战
4.3.1、一个被观察者的类Observerable 和 多个观察者Observer
public class Observerable {private ListObserver observers new ArrayListObserver();private int state;public int getState() {return state;}public void setState(int state) {notifyAllObservers();}//添加观察者public void addServer(Observer observer){observers.add(observer); }//移除观察者public void removeServer(Observer observer){observers.remove(observer); }//通知public void notifyAllObservers(int state){if(state!1){System.out.println(“不是通知的状态”);return ;}for (Observer observer : observers) {observer.doEvent();}}
}4.3.2、观察者的差异化实现 //观察者interface Observer { void doEvent();
}
//Im消息
IMMessageObserver implements Observer{void doEvent{System.out.println(发送IM消息);}
}//手机短信
MobileNoObserver implements Observer{void doEvent{System.out.println(发送短信消息);}
}
//EmailNo
EmailObserver implements Observer{void doEvent{System.out.println(发送email消息);}
}
4.3.3、EventBus实战
自己搞一套观察者模式的代码还是有点小麻烦。实际上Guava EventBus就封装好了它 提供一套基于注解的事件总线api可以灵活的使用爽歪歪。
我们来看下EventBus的实战代码哈首先可以声明一个EventBusCenter类它类似于以上被观察者那种角色Observerable。
public class EventBusCenter {private static EventBus eventBus new EventBus();private EventBusCenter() {}public static EventBus getInstance() {return eventBus;}//添加观察者public static void register(Object obj) {eventBus.register(obj);}//移除观察者public static void unregister(Object obj) {eventBus.unregister(obj);}//把消息推给观察者public static void post(Object obj) {eventBus.post(obj);}
}然后再声明观察者EventListener
public class EventListener {Subscribe //加了订阅这里标记这个方法是事件处理方法 public void handle(NotifyEvent notifyEvent) {System.out.println(发送IM消息 notifyEvent.getImNo());System.out.println(发送短信消息 notifyEvent.getMobileNo());System.out.println(发送Email消息 notifyEvent.getEmailNo());}
}//通知事件类
public class NotifyEvent {private String mobileNo;private String emailNo;private String imNo;public NotifyEvent(String mobileNo, String emailNo, String imNo) {this.mobileNo mobileNo;this.emailNo emailNo;this.imNo imNo;}}
使用demo测试
public class EventBusDemoTest {public static void main(String[] args) {EventListener eventListener new EventListener();EventBusCenter.register(eventListener);EventBusCenter.post(new NotifyEvent(13372817283, 123qq.com, 666));}
}
运行结果
发送IM消息666
发送短信消息133xxxxxxxx
发送Email消息123qq.com五、工厂模式
5.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));}
}5.2、使用工厂模式
定义工厂模式也是比较简单的:
一个工厂接口提供一个创建不同对象的方法。其子类实现工厂接口构造不同对象使用工厂模式
5.2.1、一个工厂接口
interface IFileResolveFactory{void resolve();
}5.2.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(默认文件类型解析);}
}5.2.3、使用工厂模式
//构造不同的工厂对象
IFileResolveFactory fileResolveFactory;
if(fileType“A”){fileResolveFactory new AFileResolve();
}else if(fileType“B”){fileResolveFactory new BFileResolve();}else{fileResolveFactory new DefaultFileResolve();
}fileResolveFactory.resolve();一般情况下对于工厂模式你不会看到以上的代码。工厂模式会跟配合其他设计模式如策略模式一起出现的。
六、单例模式
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;}
}枚举实现的单例代码简洁清晰。并且它还自动支持序列化机制绝对防止多次实例化。