设计模式 23个设计模式分类 总体来说设计模式分为三大类:
工厂方法模式、抽象工厂模式、单例模式、建造者(构造器)模式、原型模式。
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
责任链模式 责任链模式在框架的引用极为广泛, 例如SpringSecurity的过滤器链, Sentinel的插槽(限流, 降级, 系统保护等),他们实现就像一条链子一样 一级一级的往下走。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
建造者(构造器)模式 建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,建造者模式是一种对象创建型模式。:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,建造者模式是一种对象创建型模式。
最常见的是Lombok的@Builder
注解, 让我们使用流式创建对象。
: 每一个属性对应的方法都,返回Builder本身
通过一个public static class Builder的内部类,持有要构建对象的所有属性
设置属性的方法都返回Builder当前实例this,这样可以流式设置属性,用起来更加方便
提供一个static的Builder方法,方便用户获取Builder对象
用户通过builder对象自定义设置属性
提供build方法,创建最终对象
工厂方法模式 适用: 根据条件 判断生成什么对象
简单工厂模式 案例: 我们有一个生产课程对象的工厂(CourseFactory), 根据传入条件生产对象(JavaCourse,GoCourse…)
需求: 我们传入什么则生成什么对象
实现: 可以通过给工厂的create(自定义的创建生产的方法), 传入对象名、类名、字节码对象, 然后生产相对应的实例对象
此时的工厂模式有一个最大的特点就是工厂具体, 产品抽象, 工厂生产是根据条件生产, 只能生产一个类的课程
查看代码测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class CourseFactory { public ICourse create (Class<?> clazz) { try { if (null != clazz){ return clazz.newInstance(); } }catch (Exception e){ e.printStackTace(); } } } @Test public void test () { CourseFactory cf = new CourseFactory (); ICourse course = cf.create(JavaCourse.class); }
工厂方法模式 产品抽象, 工厂也抽象。
Java课程对应一个Java工厂, Python课程对应一个Python工厂. 在某一个特定的工厂可以根据特定的条件生产特定的产品. 解耦合
例如: List的实现, 可以发现不同的具体实例实现有不同的遍历方法(指: 迭代器). 因为不同的实现, 它们底层的数据结构实现不同, 在LinkedList底层则是链表, ArrayList则是顺序表.
追踪ArrayList的源码中实现的迭代方法Iterator
1 2 3 4 public Iterator<E> iterator () { return new Itr (); }
1 2 3 4 5 6 7 8 9 10 11 12 public E next () { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException (); Object[] elementData = ArrayList.this .elementData; if (i >= elementData.length) throw new ConcurrentModificationException (); cursor = i + 1 ; return (E) elementData[lastRet = i]; }
很容易知道, 其实就是一个顺序表的遍历
同理LinkedList遍历也是一样, 通过实现Iterator, 容易知道肯定是链表的遍历
1 2 3 4 5 6 7 8 9 10 public E next () { checkForComodification(); if (!hasNext()) throw new NoSuchElementException (); lastReturned = next; next = next.next; nextIndex++; return lastReturned.item; }
所以有: List的各种实现类, 不同的数据结构实现所实现的迭代器(工厂方法–> 用于生产产品–> 迭代器产品).
在SpringCloud Gateway中, 我们可以看到关键组件有
用于定义路由规则。谓词工厂接收一个输入(通常是一个HTTP请求),并根据定义的规则返回一个布尔值,指示该请求是否与路由匹配。
1 2 3 4 5 6 7 8 spring: cloud: gateway: routes: - id: food-service uri: lb://food-service predicates: - Path=/resfood/**
predicates: 路由断言
现在使用该模式我们可以通过,根据条件创建一个对象 , 在以往之前, 只能通过new一个具体对象
其他的案例还有: 1. Feign 2. JDK中的StringBuilder
工厂模式和策略模式组合 例如我们现在有一个需求,对于传入的不同数据进行不同的处理(比如QQ发消息,他聊天框可以发送不同类型的消息,这个是不是就可以用策略模式+工厂模式进行推送处理,即我需要对不同的数据进行不同的处理)
那么就可以使用这个组合:
我们先定义一个抽象类模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public abstract class AbstractMsgHandler <Req> { @Autowired private MessageDao messageDao; private Class<Req> bodyClass; @PostConstruct private void init () { ParameterizedType genericSuperclass = (ParameterizedType) this .getClass().getGenericSuperclass(); this .bodyClass = (Class<Req>) genericSuperclass.getActualTypeArguments()[0 ]; MsgHandlerFactory.register(getMsgTypeEnum().getType(), this ); } abstract MessageTypeEnum getMsgTypeEnum () ; protected void checkMsg (Req body, Long roomId, Long uid) { } @Transactional public Long checkAndSaveMsg (ChatMessageReq request, Long uid) { Req body = this .toBean(request.getBody()); AssertUtil.allCheckValidateThrow(body); checkMsg(body, request.getRoomId(), uid); Message insert = MessageAdapter.buildMsgSave(request, uid); messageDao.save(insert); saveMsg(insert, body); return insert.getId(); } private Req toBean (Object body) { if (bodyClass.isAssignableFrom(body.getClass())) { return (Req) body; } return BeanUtil.toBean(body, bodyClass); } protected abstract void saveMsg (Message message, Req body) ; public abstract Object showMsg (Message msg) ; public abstract Object showReplyMsg (Message msg) ; public abstract String showContactMsg (Message msg) ; }
提供一个实现类样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Component public class EmojisMsgHandler extends AbstractMsgHandler <EmojisMsgDTO> { @Autowired private MessageDao messageDao; @Override MessageTypeEnum getMsgTypeEnum () { return MessageTypeEnum.EMOJI; } @Override public void saveMsg (Message msg, EmojisMsgDTO body) { MessageExtra extra = Optional.ofNullable(msg.getExtra()).orElse(new MessageExtra ()); Message update = new Message (); update.setId(msg.getId()); update.setExtra(extra); extra.setEmojisMsgDTO(body); messageDao.updateById(update); } @Override public Object showMsg (Message msg) { return msg.getExtra().getEmojisMsgDTO(); } @Override public Object showReplyMsg (Message msg) { return "表情" ; } @Override public String showContactMsg (Message msg) { return "[表情包]" ; } }
然后我们需要提供一个工厂创建场景对象
1 2 3 4 5 6 7 8 9 10 11 12 13 public class MsgHandlerFactory { private static final Map<Integer, AbstractMsgHandler> STRATEGY_MAP = new HashMap <>(); public static void register (Integer code, AbstractMsgHandler strategy) { STRATEGY_MAP.put(code, strategy); } public static AbstractMsgHandler getStrategyNoNull (Integer code) { AbstractMsgHandler strategy = STRATEGY_MAP.get(code); AssertUtil.isNotEmpty(strategy, CommonErrorEnum.PARAM_INVALID); return strategy; } }
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 @Override @Transactional public Long sendMsg (ChatMessageReq request, Long uid) { check(request, uid); AbstractMsgHandler<?> msgHandler = MsgHandlerFactory.getStrategyNoNull(request.getMsgType()); Long msgId = msgHandler.checkAndSaveMsg(request, uid); applicationEventPublisher.publishEvent(new MessageSendEvent (this , msgId)); return msgId; }