对应Java开发工程师经常问到一定是23种设计模式,也是经常交流主题。设计模式是指定开发场景的最好代码实现。那我们就来总结一下常用的23种设计模式。Java作为面向对象设计语言,主要讲一讲面向对象设计的基本原则。(本文不写具体代码只总结,每个设计模式都写代码文章篇幅太长不易阅读)
面向对象设计原则
- 面向对象设计原则之单一职责原则
一个类只负责一个功能领域中的相应职责
- 面向对象设计原则之开闭原则
软件实体应对扩展开放,而对修改关闭
- 面向对象设计原则之里氏代换原则
所有引用基类对象的地方能够透明地使用其子类的对象
- 面向对象设计原则之依赖倒转原则
抽象不应该依赖于细节,细节应该依赖于抽象
- 面向对象设计原则之接口隔离原则
使用多个专门的接口,而不使用单一的总接口
- 面向对象设计原则之合成复用原则
尽量使用对象组合,而不是继承来达到复用的目的
- 面向对象设计原则之迪米特法则
一个软件实体应当尽可能少地与其他实体发生相互作用
六种创建型模式(处理创建类)
简单工厂模式(SimpleFactoryPattern)
image.png使用场景
- 工厂类负责创建的对象比较少(由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂)
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
工厂方法模式(FactoryMethodPattern)
image.png适用场景, 在以下情况下可以考虑使用工厂方法模式:
- 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类 的类名存储在配置文件或数据库中。
- 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要 提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和 里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
抽象工厂模式(AbstractFactoryPattern)
image.png适用场景在以下情况下可以考虑使用抽象工厂模式:
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工 厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来 使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个 产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,(如同一操作 系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统 的,此时具有一个共同的约束条件:操作系统的类型。)
- 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的 产品等级结构。
单例模式(SingletonPattern)
适用场景 在以下情况下可以考虑使用单例模式:
- 系统只需要一个实例对象,(如系统要求提供一个唯一的序列号生成器或资源管理器或者需要考虑资源消耗太大而只允许创建一个对象)
- 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
原型模式(PrototypePattern)
适用场景在以下情况下可以考虑使用原型模式:
- 创建新对象成本较大(如初始化需要占用较长的时间,占用太多的CPU资源或网络资源),新的对象可以通过原型模式对已有对象进行复制来获得,如果是相似对象,则可以对 其成员变量稍作修改。
- 如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占用内存较少时,可以使用原型模式配合备忘录模式来实现。
- 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。
建造者模式(BuilderPattern)
在以下情况下可以考虑使用建造者模式:
- 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
- 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
- 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
七个结构型模式(处理类实例与类实例关系)
适配器模式(AdapterPattern)
image.png- 对象适配器模式
- 类适配器模式
适用场景
- 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。
- 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可 能在将来引进的类一起工作。
桥接模式(BridgePattern)
组合模式(CompositePattern)
image.png适用场景 在以下情况下可以考虑使用组合模式:
- 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以 一致地对待它们。
- 在一个使用面向对象语言开发的系统中需要处理一个树形结构。
- 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新 的类型。
装饰模式(DecoratorPattern)
- 透明装饰模式
- 半透明装饰模式
适用场景
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装 饰模式。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每 一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类已定义为不能被继承(如Java语言中的final类)。
外观模式(FacadePattern)
外观模式模式适用场景
- 当要为访问一系列复杂的子系统提供一个简单入口时可以使用外观模式。
- 客户端程序与多个子系统之间存在很大的依赖性。引入外观类可以将子系统与客户端解耦,从而提高子系统的独立性和可移植性。
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
享元模式(FlyweightPattern)
代理模式(ProxyPattern)
- 静态代理
- 动态代理
模式适用场景,代理模式的类型较多,不同类型的代理模式有不同的优缺点,它们应用于不同的场合:
- 当客户端对象需要访问远程主机中的对象时可以使用远程代理。
- 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、 缩短运行时间时可以使用虚拟代理,例如一个对象需要很长时间才能完成加载时。
- 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问 这些结果时可以使用缓冲代理。通过使用缓冲代理,系统无须在客户端每一次访问时都重新 执行操作,只需直接从临时缓冲区获取操作结果即可。
- 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代 理。
- 当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能引用代理。
十一个行为型模式(处理类与类之间行为(方法)关系)
职责链模式(ChainofResponsibilityPattern)
适用场景
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只 需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可以改变链中 处理者之间的先后次序。
命令模式(CommandPattern)
解释器模式(InterpreterPattern)
迭代器模式(IteratorPattern)
观察者模式(ObserverPattern)
适用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对 象......,可以使用观察者模式创建一种链式触发机制。
策略模式(StrategyPattern)
适用场景
- 一个系统需要动态地在几种算法中选择一种,那么可以将这些算法封装到一个个的具体算 法类中,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一 的接口,根据“里氏代换原则”和面向对象的多态性,客户端可以选择使用任何一个具体算法 类,并只需要维持一个数据类型是抽象算法类的对象。
- 一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重条件选择语句来 实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难 以维护的多重条件选择语句。
- 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法与相关的数 据结构,可以提高算法的保密性与安全性。
模板方法模式(TemplateMethodPattern)
模式适用场景
- 对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方 法,而一些可以改变的细节由其子类来实现。即:一次性实现一个算法的不变部分,并将可 变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
- 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
网友评论