常用设计模式
单例模式
(关键:new 一个 static 对象)
- 一个类只有一个示例,最典型就是Sping Ioc。
优点
- 只有一个对象,节省资源,提高系统性能。
- 避免共享资源被重复占用,如程序计数器、资源文件的访问,对线程安全有一定帮助。
- 允许可变数目的实例,自己new就可以。
缺点
- 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
- 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
应用场景
- Spring Ioc
- 程序中的计数器。
- windows系统下的任务管理器,试试看,只能打开一个。
- 需要频繁实例化然后销毁的对象。
- 创建对象时耗时过多或者耗资源过多,但又经常用到的对象,而且不变化的对象。
- 有状态的工具类对象。
- 频繁访问数据库或文件的对象。
总结
单例模式一般出现在以下情况下:
- 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
- 控制资源的情况下,方便资源之间的互相通信。如线程池等。
简单工厂模式
(关键:new对象的逻辑放到工厂中)
优点
- 封装:将逻辑封装到接口中。
- 解耦:本来要自己new对象的,耦合度比较强,现在放到工厂中。
缺点
- 增加实例,就要修改工厂类。破坏了开闭原则,还是存在一些耦合,所以才会有工厂方法模式。
应用场景
- 很多要对数据进行判断处理的都需要这么做。
- Spring的BeanFactory
工厂方法模式
(关键:为了解决简单工厂违背开闭原则的缺陷,不需要将逻辑放到工厂中,而是每个实例就创建一个工厂类,用于处理相关逻辑)
优点
- 克服了简单工厂违背开放-封闭原则的缺点,又保留了封装对象创建过程的优点,降低客户端和工厂的耦合性,所以说“工厂模式”是“简单工厂模式”的进一步抽象和推广。
缺点
- 每增加一个产品,相应的也要增加一个子工厂,加大了额外的开发量。
- 代码还是和子工厂耦合在一起,出现变动时会比较麻烦。
应用场景
- 很多地方都可以用到,有时还可以和简单工厂一起使用。
抽象工厂模式
区别
工厂方法模式:
- 一个抽象产品类,可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
- 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类可以创建多个具体产品类的实例。
区别:
- 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
- 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
优点
- 在工厂方法的基础上,对产品做更细致的抽象。
- 更强的灵活性。
缺点
- 工作量更多。
代理模式
(关键:在我们的实现类外面再包一层,以达到我们想要实现的功能)
优点
- 解耦,职责更清晰,关节业务和我们需要加的功能分离开。
- 保护目标对象,在客户端和目标对象之间形成一个中介,可以记录过程和保护目标对象。
- 高扩展性,以后可以修改代理而不修改目标对象。
缺点
- 额外开发工作
- 由于在客户端和真实对象之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢
应用场景及分类
- 远程代理:为不同地理的对象提供局域网代表对象。
- 虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。
- 保护代理:控制对一个对象的访问权限。
- 智能引用代理:提供对目标对象额外的一些服务,如记录日志。
- Cache代理
- 防火墙代理
- 同步化代理
命令模式
(关键:某个方法需要完成某一个功能,完成这个功能的大部分步骤已经确定了,但可能有少量具体步骤无法确定,必须等到执行该方法时才可以确定。在方法参数中加一个命令对象作为参数,当执行时调用命令对象的方法。)
优点
- 将少数不相同的步骤解耦出来。
- 新的命令很容易加入到系统中,并且可以方便的制定各种命令和利用现有命令组合出新的命令。
- 调用同一个方法,实现不同功能。
缺点
- 开发量增加
适用场景
- 当需要对行为进行“记录、撤销/重做”等处理时。
- 系统需要将请求者和接收者解耦,使得调用者和接收者不直接交互。
- 系统需要在不同时间指定请求、请求排队和执行请求。
- 系统需要将一组操作组合在一起,即支持宏命令。
策略模式
(关键:建一个Context,相当于一个工厂,用于判断执行什么算法,每个算法一个类)
优点
- 在解耦的同时,减少重复代码。
- 原本逻辑和算法耦合在客户端,现在把算法抽出来,然后把判断用什么算法的逻辑也抽出来,职责更加单一明显,维护更加方便。
- 更符合开闭原则,当需要加新算法或需要修改逻辑时,只要加新的算法类和修改Context就好,不要改客户端。
缺点
- 增加开发量。
- 有可能会造成很多的策略类。
适用场景
- 几个类的主要逻辑相同,只在部分逻辑的算法和行为上稍有区别的情况。
- 有几种相似的行为,或者说算法,客户端需要动态地决定使用哪一种,那么可以使用策略模式,将这些算法封装起来供客户端调用。
桥接模式
(关键:将现实中的多维度变化抽象出来,例如,小车在高速公路上行驶,小车在街道上行驶,巴士在高速公路上行驶,巴士在街道上行驶;可以拆分成马路接口,高速公里和街道来实现,将车拆分成车辆接口,小车和巴士来实现)
优点
- 分离抽象和实现部分,将马路和车辆分来两个接口,分工更加明确。
- 更好的扩展,如果加实现类都会比较方便。
- 动态地切换实现,组合方便。
- 减少子类个数,更好地维护。
缺点
- 暂时没发现,只要别乱用就好。
适用场景
- 如果不想抽象和实现绑定在一起的话,就可以用。
- 当想要更多组合,减少子类的情况,也可以用。
观察者模式
(关键:建立一个观察者List和一个被观察对象,将观察者加入List或从List中移除,如果有通知,就向List中的每个观察者通知)
优点
- 观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
- 观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知。
缺点
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
- 如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
- 虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
适用场景
在主业务中,附带了很多其他操作,例如电影购票的核心记录,在核心业务之余,还要加上其他附带的操作。
- 购票后记录文本日志
- 购票后记录数据库日志
- 购票后发送短信
- 购票送抵扣卷、兑换卷、积分
- 其他各类活动等
实现:创建一个观察者接口,一个主题接口,购票核心业务实现主题接口,其他附带操作实现观察者借口。
解决问题
- 一旦某个业务逻辑发生改变,如购票业务中增加其他业务逻辑,需要修改购票核心文件、甚至购票流程。
- 日积月累后,文件冗长,导致后续维护困难。
- 更松的耦合度。
http://blog.csdn.net/xsl1990/article/details/16359289