面向对象
设计模式
http://c.biancheng.net/view/1317.html
First of all,组合一般优于继承。
创建模式
工厂方法是类创建型,其他属于对象创建型。
单例模式Singleton
饿汉模式,懒汉模式(volatile + synchronized + double check)
原型模式Prototype
例子:Jave的clone()
简单工厂模式
简单工厂模式的工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。不修改代码的话,是无法扩展的。
不属于GoF,会违背开闭原则
创建产品的逻辑在一个方法里,增加产品要修改代码
工厂方法模式FactoryMethod
工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。
在同一等级结构中,支持增加任意产品。
是对简单工厂的抽象,不同产品有对应的工厂。只要知道工厂,就能得到产品。
例子:Spring的FactoryBean
例子1:java.sql的Connection
DriverManager是这个抽象工厂,Connection是不同的产品的接口,Driven是不同产品的接口。
1 | Connection con = DriverManager.getConnection( |
抽象工厂模式AbstractFactory
抽象工厂是应对产品族概念的。比如说,每个汽车公司可能要同时生产轿车,货车,客车,那么每一个工厂都要有创建轿车,货车和客车的方法。
增加汽车公司容易,增加车的类型难?——增加车的类型得改所有的汽车公司..
建造者模式Builder
例子:lombok的@Builder
注重零部件的组装过程,工厂方法模式注重零部件的创建过程,两者可以结合使用。
结构型模式
将类或对象按某种布局组成更大的结构。
分为类结构型和对象结构型,前者继承机制,后者组合或聚合来组合对象。
适配器分为结构型和对象型,其他都是对象型。
代理模式Proxy
为某对象提供一种代理,以控制对该对象的访问,限制、增强或修改该对象的一些特性。
例子:JDK动态代理
适配器模式Adapter
将一个类的接口转换成客户希望的另外一个接口
例子:Gson的TypeAdapter,是json和Type之间的适配器
和策略一样,只不过意图不同,适配器根据策略返回对象,对象再继续执行不同的逻辑?
桥接模式Bridge
将抽象和实现分离,用组合关系代替继承关系 —— 很糊,不清楚
https://juejin.im/post/6844903919982739469
每个驱动程序都是适配器模式 (Adapter) 的一个例子, 而使用驱动程序的应用是桥接模式的一个例子. 桥接模式将应用的开发和驱动的开发分离开来.
Bridge, State, Strategy (Adapter 在某种程度上也算) 有一些相似, 这些设计模式都采用了将功能代理给其它类去做的方式. 但是, 他们解决的问题并不相同.
Abstract Factory 可以和 Bridge 一起使用(比如驱动程序的例子), 通常用于 Abstraction 只能使用特定的 Implementation 的情况. 在这种情况下, 可以用 Abstract Factory 封装 Client 代码中建立 Abstraction 和 Implementation 连接的部分.
装饰模式Decorator
增加额外的功能 —— 感觉和代理很像
https://zhuanlan.zhihu.com/p/97499017
让别人帮助你做你并不关心的事情,叫代理模式【代理模式强调要让别人帮你去做一些本身与你业务没有太多关系的职责(记录日志、设置缓存)。代理模式是为了实现对象的控制,因为被代理的对象往往难以直接获得或者是其内部不想暴露出来。】
为让自己的能力增强,使得增强后的自己能够使用更多的方法,拓展在自己基础之上的功能的,叫装饰器模式【增强后你还是你,只不过能力更强了而已】
外观模式Facade
为多个复杂的子系统提供一个一直的接口,使子系统更容易被访问
简单理解:对内部复杂的逻辑进行封装,或者不想暴露太多
例子
https://blog.csdn.net/weixin_34416649/article/details/87998378
org.springframework.jdbc.support.JdbcUtils getResultSetValue
org.apache.ibatis.session.Configuration的newExecutor等
Tomcat的getRequest()取到的是RequestFacade,RequestFacade是对HttpServletRequest的有限or更简单的访问
slf4j是简单的日志外观模式框架,可以有logback、log4j、Commons-logging和JDK自带的logging等各种实现
享元模式Flyweight
运用共享技术,支持大量细粒度对象的复用
例子
https://juejin.im/post/6844903683860217864
- String在jvm字符串常量中的复用
- Integer中-128~127的复用
- 数据库连接池复用
组合模式Composite
将对象组合成树状层次结构,使用户对单个对象和组合对象有一致的访问性。
例子
https://juejin.im/post/6844903687228407821
putAll
接收的参数为父类Map
类型,所以HashMap
是一个容器类,Map
的子类为叶子类,如果Map
的其他子类也实现了putAll
方法,那么它们都既是容器类,又都是叶子类同理,
ArrayList
中的addAll(Collection<? extends E> c)
方法也是一个组合模式的应用
1
2
3
4 > public void putAll(Map<? extends K, ? extends V> m) {
> putMapEntries(m, true);
> }
>
行为模式
描述多个类或对象之间怎样协作完成单个对象无法单独完成的任务
分为类行为模式和对象行为模式,前者继承机制在类间分派行为,后者组合或聚合再对象间分配行为。
模板方法Template Method
定义算法骨架,将算法具体步骤延迟到子类
使得子类在可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
例子
https://juejin.im/post/6844903689103081479
- Servlet的doGet、doPost等
- mybatis的BaseExecutor。
BaseExecutor
的子类有四个分别是SimpleExecotor
、ReuseExecutor
、BatchExecutor
、ClosedExecutor
,由于这里使用了模板方法模式,一级缓存等固定不变的操作都封装到了BaseExecutor
中,子类就不必再关心一级缓存等操作,只需要专注实现4个基本方法的实现即可。这四个方法分别是:doUpdate()
方法、doQuery()
方法、doQueryCursor()
方法、doFlushStatement()
方法,其余功能都在BaseExecutor
中实现。
策略模式Strategy
定义一系列算法,每个算法封装起来,可以相互替换
例子很多了,Gson里的TypeAdapter,用哪个Adapter也是策略吧
命令模式Command
暂时没用过…
责任链模式Chain of Responsiblity
为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
优点:
- 降低了对象之间的耦合度。
- 增强了系统的可扩展性。
- 增强了给对象指派职责的灵活性。
- 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
- 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
主要缺点:
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
例子:
- Servlet的Filter等
- netty的boundIn和boundOut handler
状态模式State
https://alphagao.com/2017/08/07/stragety-pattern-vs-state-pattern/
策略模式关注的焦点在于具体的某一个行为,准确的说是某一行为的具体执行过程。策略模式中具体行为策略的改变是由调用方主动指定的。
状态模式关注的焦点在于内部状态的改变而引起的行为的变化。不需要调用方干涉。
观察者模式Observer
https://juejin.im/post/6844903697781096455
spring的事件机制是从java的事件机制拓展而来,
ApplicationContext
中事件处理是由ApplicationEvent
类和ApplicationListener
接口来提供的。如果一个Bean实现了ApplicationListener
接口,并且已经发布到容器中去,每次ApplicationContext
发布一个ApplicationEvent
事件,这个Bean就会接到通知
- ApplicationContext:事件源,其中的 publishEvent()方法用于触发容器事件
- ApplicationEvent:事件本身,自定义事件需要继承该类,可以用来传递数据
- ApplicationListener:事件监听器接口,事件的业务逻辑封装在监听器里面
中介者模式Mediator
不清楚
迭代器模式Iterator
访问者模式Visitor
备忘录模式Memento
解释器模式Interpreter
面向对象
简单说一下面向对象的特征以及六大原则
特征:
封装:把客观事物封装成抽象的类
抽象继承!:(实现继承or接口继承)让某个类型的对象获得另一个类型的对象的属性和方法多态:一个类实例的相同方法在不同情形有不同的表现形式。(编译多态与运行时多态)一般指运行时多态..?
多态存在的必要条件:继承、重写、父类引用指向子类对象
原则:
单一职责:一个类的功能要单一,不能包罗万象
开放封闭:一个模块,在扩展性方面应该是开发的,在更改性方面是封闭的
里氏替换:子类应当可以替换父类,并出现在父类能够出现的任何地方
依赖倒置:高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象;抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
接口分离:模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来,即面向接口编程。
迪米特原则:一个类对自己依赖的类知道的越少越好。类间解耦,低耦合、高内聚。