讲起设计模式,首先得谈及面对对象的七个原则
面对对象的七大原则
- 开放封闭原则:对扩展开放,对修改关闭,模块应该在尽量不修改源代码的情况下扩展。
- 单一职责原则:一个类只做一件事。
- 依赖倒换原则:程序要依赖于抽象接口,而不是具体实现,降低客户与实现模块之间的耦合。
- 迪米特原则,也称最小知识原则:高内聚,低耦合。
- 接口隔离原则:客户端不要依赖它不需要的接口上,类间的依赖关系建立在最小的接口上。
- 合成复用原则:尽量使用合成,尽量不要使用继承。
- 里氏代换原则:子类不能去修改父类的内容。
面对对象的设计模式
设计模式是一套被反复使用、多数人知晓、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码,让代码更容易让他人理解,提高代码的可靠性。
1. 简单工厂模式
简单工厂模式可根据你参数的不同返回不同类的实例,被创建的实例通常都拥有共同的父类,属于类创建型模式。
主要包含工厂角色、抽象产品角色、具体产品角色
2. 工厂方法模式
在工厂方法模式中,不再提供一个统一的工厂来创建所有对象,而是针对不同的产品提供不同的工厂,系统提供一个和产品等级结构对应的工厂等级结构。工厂方法模式定义一个用于创建对象的接口,由子类决定将哪一个类实例化。
同简单工厂模式,工厂模式引入了一个抽象工厂角色,它可以是接口,也可以抽象类或是具体类。使得系统可以在不修改工厂角色的情况下引入新产品。
设计步骤:
- 创建抽象工厂类,定义具体工厂的统一接口;
- 创建抽象产品类,定义具体产品的统一接口;
- 创建具体产品类(继承抽象产品类);
- 创建具体工厂类(继承抽象工厂类);
- 外界通过调用具体工厂类的方法,创建具体产品类的实例。
主要优点和缺点
主要优点:
- 用户在使用时只用关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名。
- 基于工厂角色和产品角色的多态性是工厂模式的关键,它能够让工厂自主确定创建何种产品,而如何创建的细节完全封装在具体工厂内部。
- 在系统添加新产品时,无需修改抽象产品和抽象工厂提供的接口,无需修改客户端和其他具体工厂和具体对象,只用添加一个具体对象和具体工厂就可以了,系统的可扩展性变得非常好,完全符合“开闭原则”。
主要缺点:
- 添加新产品时,需要额外加一个具体产品类和具体工厂类,类的个数成对增加,一定程度上增加了系统的复杂度,会给系统带来一些额外的开销。
- 抽象层的使用增加了系统的抽象性和理解难度,且实现时可能用到DOM、反射等技术,增加了系统的实现难度。
适用场景
- 客户端不知道它所需要对象的类。只需要知道产品多对应的工厂。
- 抽象工厂类通过其子类来指定创建哪个对象。
3. 单例模式
为了确保对象的唯一性,我们可以采用单例模式。
单例模式的特点
- 某个类只能有一个实例
- 它必须自行创建这个实例
- 它必须自行向整个系统提供这个实例
饿汉单例模式
- 优点:程序加载就进行实例化,之后的操作效率会很高。
- 缺点:由于程序加载就进行实例化,如果后续对此类不进行任何操作,就会导致内存的浪费。
懒汉单例模式
- 优点:第一次调用时才进行实例化
- 缺点:当多个线程进入时,会创建多个对象。
单例模式的主要优点和缺点
优点
- 单例模式提供了对唯一实例的受控访问。
- 由于系统只有一个对象,可以节约资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
- 基于单例模式,我们可以进行扩展,指定对象实例的数目。
缺点
- 由于单例模式没有抽象层,所以它的扩展有很大的困难。
- 单例类的职责过重,一定程度上违背了“单一职责原则”。
- 现在很多面对对象的语言都提供了垃圾回收站,因此如果实例的对象长时间不用,系统会认为是垃圾,自动销毁并释放资源,下次使用又重新实例化,这将导致共享的单例对象状态的丢失。
适用场景
- 系统只需要实例化一个对象,或者需要考虑资源消耗太大而只允许创建一个对象。
- 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
- 典型应用场景,日志文件,网站计数器,应用配置。控制资源的情况下,方便资源之间的互相通信,如线程池,数据库连接池等。
观察者模式
模式动机:建立一套低耦合的消息触发机制。建立对象间一对多的关联关系,并能使一个对象的变化使所有对象感知。每当一个对象状态发生改变,其相关依赖对象皆得到通知并自动更新。
分为观察目标和观察者两个继承层次结构。
观察者模式的优缺点:
优点:
- 观察者模式实现表现层和数据逻辑层之间的分离,定义了稳定的消息更新传递机制,并抽象了更新接口,使得各种各样不同的表现层充当具体观察者角色。
- 观察者模式在观察者和观察目标之间建立一个抽象的耦合。
- 观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
- 观察者模式满足“开闭原则”的要求,增加新的具体观察者,无需修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。
缺点:
- 如果一个观察目标有多个直接和间接观察者,将所有观察者都通知将花费很多时间。
- 如果观察者和观察目标之间存在循环依赖,观察目标会触发它们之间的循环调用,可能会导致崩溃。
- 观察者模式没有相应的机制让观察者知道所观察的目标是怎么变化的,而仅仅只是知道观察目标发生了变化。
适用场景
- 一个抽象模型有两个方面,一个方面依赖另一个方面,将两个方面封装在独立的对象中,使它们可以各自独立的改变和复用。
- 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象发生改变,也不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象......,可以使用观察者模式创建一种链式触发机制。