设计模式简述

设计模式

设计模式,就是一套被反复使用的代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式分为三类:

创建型:

对类的实例化过程的抽象化。单例模式、工厂模式、抽象工厂模式、原型模式、建造者模式。

结构型:

描述如何将类或对象结合在一起形成更大的结构。适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式等

行为型:

对在不同的对象之间划分责任和算法的抽象化。模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式、访问者模式。

   共 23 种设计模式,包括:Abstract Factory(抽象工厂模式),Builder(建造者模式),Factory Method(工厂方法模式),Prototype(原始模型模式),Singleton(单例模式);Facade(门面模式),Adapter(适配器模式),Bridge(桥梁模式),Composite(合成模式),Decorator(装饰模式),Flyweight(享元模式),Proxy(代理模式);Command(命令模式),Interpreter(解释器模式),Visitor(访问者模式),Iterator(迭代子模式),Mediator(调停者模式),Memento(备忘录模式),Observer(观察者模式),State(状态 模式 ),Strategy(策略 模式 ),Template Method(模板方法模式),Chain Of Responsibility(责任链模式)

几个常用的设计模式:

1、单例模式:一个类只有一个实例,即一个类只有一个对象实例。

使用场景:
	 1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置、枚举。使用枚举其实和使用静态类内部加载方法原理类似。
	 2)控制资源的情况下,方便资源之间的互相通信。如线程池等。

注意:
1、使用时不能用反射模式创建单例,否则会实例化一个新的对象
2、使用懒单例模式时注意线程安全问题。要是由于 uniqueInstance 被多次实例化。只需要对 懒汉式getUniqueInstance() 方法加锁/双重校验锁等。
3、饿单例模式和懒单例模式构造方法都是私有的,因而是不能被继承的,有些单例模式可以被继承(如登记式模式)
懒汉式单例模式,线程不安全,致命的是在多线程不能正常工作
饿汉式单例模式,避免了多线程的同步问题

2、简单工厂模式

 简单工厂模式(静态方法模式):将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,实现了解耦。简单工厂模式违背了开发-关闭原则,一旦变更产品,就需要修改工厂类的逻辑。

使用步骤
1、创建抽象产品类& 定义具体产品的公共接口;
2、创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
3、创建工厂类,通过创建静态方法根据传入不同参数从而创建不同具体产品类的实例;
4、外界通过调用工厂类的静态方法,传入不同参数从而创建不同具体产品类的实例

3、工厂方法模式(工厂模式、多态工厂模式和虚拟构造器模式)

  通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。

优点:
1、符合开放-封闭原则。新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
2、符合单一职责原则。每个具体工厂类只负责创建对应的产品
3、不使用静态工厂方法,可以形成基于继承的等级结构。

缺点:
1、添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
2、由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
3、虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
4、一个具体工厂只能创建一种具体产品

4、抽象工厂模式

  提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类;具体的工厂负责实现具体的产品实例。
  抽象工厂模式与工厂方法模式最大的区别:抽象工厂中每个工厂可以创建多种类的产品;而工厂方法每个工厂只能创建一类。

使用步骤:
步骤1:创建抽象工厂类,定义具体工厂的公共接口;
步骤2:创建抽象产品族类,定义抽象产品的公共接口;
步骤3:创建抽象产品类(继承抽象产品族类),定义具体产品的公共接口;
步骤4:创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
步骤5:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
步骤6:客户端通过实例化具体的工厂类,并调用其创建不同目标产品的方法创建不同具体产品类的实例

优点:降低耦合;针对性符合开-闭原则;符合单一职责原则;不使用静态工厂方法,可以形成基于继承的等级结构
缺点:抽象工厂模式很难支持新种类产品的变化。对于旧的产品族符合开-闭原则;对于新的产品种类不符合开-闭原则,这一特性称为开-闭原则的倾斜性。

5、策略模式

      准备一组算法 & 将每一个算法封装起来,让外部按需调用 & 使得互换。策略模式仅仅封装算法(包括添加 & 删除),但策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。

应用场景:
   动态选择多种复杂行为。该行为可理解为:复杂的算法 / 数据结构;类的行为 / 方法。常用于活动的内部计算优惠等方法。

6、适配器模式:

   把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。

  适配器模式的形式分为:类的适配器模式 & 对象的适配器模式
  1、类的适配器模式。把适配的类的API转换成为目标类的API。(用继承关系区分)常见的XXServiceImpl继承ServiceImpl并实现XXIService。
  2、对象的适配器模式。也是把适配的类的API转换成为目标类的API。使用委派关系连接到Adaptee类。

优点

1、更好的复用性。系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
2、透明、简单。客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单 & 更直接
3、更好的扩展性。在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。
4、解耦性。将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码
5、符合开放-关闭原则。同一个适配器可以把适配者类和它的子类都适配到目标接口;可以为不同的目标接口实现不同的适配器,而不需要修改待适配类

缺点
	过多的使用适配器,会让系统非常零乱,不易整体进行把握

7、静态代理模式

给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用

使用步骤

步骤1: 创建抽象对象接口(Subject):声明你(真实对象)需要让代购(代理对象)帮忙做的事(买Mac)

步骤2: 创建真实对象类(RealSubject),即”我“。真实对象需实现抽象对象接口

步骤3:创建代理对象类(Proxy),也需要实现抽象对象接口,即”代购“,并通过代理类创建真实对象实例并访问其方法

步骤4:客户端调用

优点
1、协调调用者和被调用者,降低了系统的耦合度
2、代理对象作为客户端和目标对象之间的中介,起到了保护目标对象的作用

缺点
1、由于在客户端和真实主题之间增加了代理对象,因此会造成请求的处理速度变慢;
2、实现代理模式需要额外的工作(有些代理模式的实现非常复杂),从而增加了系统实现的复杂度。

8、动态代理模式

   动态代理类(DynamicProxy)不需要显式实现与目标对象类(RealSubject)相同的接口,而是将这种实现推迟到程序运行时由JVM来实现。JVM 通过Java反射机制的method.invoke(),通过调用动态代理类对象方法,从而自动调用目标对象的方法。

   即:在使用时再创建动态代理类 & 实例,静态代理则是在代理类实现时就指定与目标对象类(RealSubject)相同的接口。

优点
1、只需要1个动态代理类就可以解决创建多个静态代理的问题,避免重复、多余代码
2、更强的灵活性

缺点
1、效率低。相比静态代理中直接调用目标对象方法,动态代理则需要先通过Java反射机制从而间接调用目标对象方法
2、应用场景局限。因为 Java 的单继承特性(每个代理类都继承了 Proxy 类),即只能针对接口创建 代理类,不能针对类创建代理类,即只能动态代理实现了接口的类

应用场景
1、基于静态代理应用场景下,需要代理对象数量较多的情况下使用动态代理
2、AOP领域即面向切面编程,是OOP的延续、函数式编程的一种衍生范型

作用:通过预编译方式和运行期动态代理实现程序功能的统一维护。
优点:降低业务逻辑各部分之间的耦合度 、 提高程序的可重用性 & 提高了开发的效率

具体应用场景:日志记录、性能统计、安全控制、异常处理等
使用步骤

步骤1: 声明 调用处理器类DynamicProxy.java
步骤2: 声明目标对象的抽象接口Subject.java
步骤3: 声明目标对象类Buyer1.java Buyer2.java(需继承抽象接口)
步骤4: 通过动态代理对象,调用目标对象的方法MainActivity.java(利用java反射)

9.外观模式

   定义了一个高层、统一的接口,外部与通过这个统一的接口对子系统中的一群接口进行访问。例如:首页导航搜索等。

主要作用
1、实现客户类与子系统类的松耦合
2、降低原有系统的复杂度
3、提高了客户端使用的便捷性,使得客户端无须关心子系统的工作细节,通过外观角色即可调用相关功能。

10、观察者模式

在对象之间定义一对多的依赖, 这样一来, 当一个对象改变状态, 依赖它的对象都会收到通知, 并自动更新。

总结:

单例模式 一般用于配置文件、枚举类等全局配置场景
策略模式  一般用于特定事件需要封装算法、结构,
适配器模式 一般用于代码中功能数据处理,serviceImpl
静态代理模式  用于远程代理、虚拟代理
动态代理模式  常用于日志记录、安全控制等(AOP面向切面编程)。
外观模式  常用于导航搜索
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值