设计模式~

四、设计模式

设计模式六大原则
(1)单一职责原则——一个类应该只负责一项职责
(2)迪米特原则——一个对象应该对其他对象保持最少的了解。
(3)里氏代换原则——所有引用基类(父类)的地方必须能透明地使用其子类的对象。
(4)接口隔离原则——一个类对另一个类的依赖应该建立在最小的接口上
(5)依赖倒置原则——高层模块不应该依赖低层模块,二者都应该依赖其抽象
(6)开闭原则——一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

1.单例模式(创建型设计模式)
一个类只有一个实例,且该类能自行创建这个实例的一种模式
优点:
单例模式可以保证内存里只有一个实例,减少了内存的开销。
可以避免对资源的多重占用。

缺点:
单例模式一般没有接口,扩展困难,违背开闭原则
(1)饿汉式。避免了线程同步问题,没有达到懒加载的效果
(2)懒汉式。(双重检查,线程安全;延迟加载;效率较高)
(3)静态内部类。避免了线程不安全,延迟加载,效率高。
(4)枚举。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
使用场景
(1)需要频繁的进行创建和销毁的对象;
(2)创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
(3)工具类对象;
(4)频繁访问数据库或文件的对象。

场景
图片的缓存LruChache、数据库访问对象、工具类

ActivityManager中管理Activity堆栈

2.建造者模式(创建型设计模式)
将一个复杂对象的创建与它的表示分离,使得同样的构造过程可以创建不同的表示。

优点:
良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成的细节;
建造者独立,容易扩展;
缺点:
产生多余的Builder以及Director对象,消耗内存;

(1)抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建。
(2)具体建造者类(ConcreteBuilder):实现Builder接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。
(3)产品类(Product):要创建的复杂对象。
(4)指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

场景
AlertDialog的构建过程
OkHttpClient的构建过程

3.工厂模式(创建型设计模式)
创建对象和第三方调用者相隔离,这样对象的提供方和调用方的耦合关系就会减小。

(1)简单工厂(Simple Factory)
定义:一个工厂方法,依据传入的参数,生成对应的产品对象;
缺点:新添加产品的时候就需要修改工厂里面的代码

工厂类角色:该模式的核心,用来创建产品,含有一定的商业逻辑和判断逻辑
抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
具体产品角色:工厂类所创建的对象就是此角色的实例。

(2)工厂
对简单工厂模式进一步的解耦,在工厂方法模式中是一个子类对应一个工厂类,而这些工厂类都实现于一个抽象接口
优点:各个不同功能的实例对象的创建代码,也没有耦合在同一个工厂类里,而是抽象了一个工厂接口作为扩展点,这也是工厂方法模式对简单工厂模式解耦的一个体现。
缺点:工厂方法模式的缺点是每增加一个java类,就需要增加一个对应的工厂类,当我们的类很多的时候,那么对应的工厂类也会很多

抽象工厂 AbstractFactory: 工厂方法模式的核心,是具体工厂角色必须实现的接口或者必须继承的父类,在 Java 中它由抽象类或者接口来实现。
具体工厂 Factory:被应用程序调用以创建具体产品的对象,含有和具体业务逻辑有关的代码
抽象产品 AbstractProduct:是具体产品继承的父类或实现的接口,在 Java 中一般有抽象类或者接口来实现。
具体产品 Product:具体工厂角色所创建的对象就是此角色的实例。

(3)抽象工厂
优点:相比于工厂方法模式不用一直创建新的对应的类的小工厂,扩展性更加,不会使代码越来越多,越复杂,把生产对象的过程抽象化,这样就可以和业务逻辑解耦,如果有新扩展,可以在IOHandlerFactory中增加对应的方法。

抽象工厂 AbstractFactory:定义了一个接口,这个接口包含了一组方法用来生产产品,所有的具体工厂都必须实现此接口。
具体工厂 ConcreteFactory:用于生产不同产品族,要创建一个产品,用户只需使用其中一个工厂进行获取,完全不需要实例化任何产品对象。
抽象产品 AbstractProduct:这是一个产品家族,每一个具体工厂都能够生产一整组产品。
具体产品 Product

工厂方法模式与抽象工厂模式的区别在于:
(1)工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类,每个具体工厂类只能创建一个具体产品类的实例。
(2)抽象工厂模式拥有多个抽象产品类(产品族)和一个抽象工厂类,每个抽象产品类可以派生出多个具体产品类;抽象工厂类也可以派生出多个具体工厂类,同时每个具体工厂类可以创建多个具体产品类的实例

场景
BitmapFactory–简单工厂
Retrofit–抽象工厂

4.装饰器模式(结构型设计模式)
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式生成子类更为灵活;
装饰模式是对所要装饰的对象的功能增强,而代理模式只是对代理的对象进行调用,不会对对象本身的功能有所增强;

优点
采用组合的方式,可以动态的扩展功能,同时也可以在运行时选择不同的装饰器,来实现不同的功能。
有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
被装饰者与装饰者解偶,被装饰者可以不知道装饰者的存在,同时新增功能时原有代码也无需改变,符合开放封闭原则。

缺点
装饰层过多的话,维护起来比较困难。
如果要修改抽象组件这个基类的话,后面的一些子类可能也需跟着修改,较容易出错。

Component:抽象构件,是定义一个对象接口,可以给这个对象动态地添加职责。
ConcreteComponent:具体构件,是定义了一个具体的对象,也可以给这个对象添加一些职责。
Decorator:抽象装饰类,继承自 Component,从外类来扩展 Component 类的功能,但对于 Component 来说,是无需知道 Decorator 存在的。
ConcreteDecorator:具体装饰类,起到给 Component 添加职责的功能。

场景
IO流的缓冲流
Context、ContextImpl、ContextWrapper

5.代理模式(结构型设计模式)
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,
而代理对象可以在客户端和目标对象之间起到中介的作用。这样做的好处是降低了耦合性,而且具有方法增强、高扩展性的设计优势

静态代理
1.自己手工实现的代理类.
2.代理的目标类是固定的.

优点:
实现简单,容易理解.

缺点:
目标类增多对应的代理类成倍增加.
当接口的方法进行添加修改时,会影响到众多类实现类需要修改,大大增加出错率.

动态代理
在程序执行过程中,使用jdk的反射机制,InvocationHandler invoke创建代理类对象,并动态的制定要代理目标类.

优点:
代理类数量可以很少.
当你修改了接口中的方法时,不会影响代理类.

场景:
Binder进程间通信原理,通过AIDL实现进程间通信,都会生成代理类,最终客户端通过代理类调用远程服务的方法;
Retrofit的实现

动态代理和静态代理的区别
代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问
1、静态代理只代理一个类,而动态代理是代理接口下的多个实现类
2、静态代理在编译时就知道要代理的类,而动态代理是在运行期动态生成的代理类。
3 、动态代理类不需要实现接口,但是委托类还是需要实现接口。

Subject:抽象角色,声明了真实对象和代理对象的共同接口;
Proxy:代理角色,实现了与真实对象相同的接口,所以在任何时刻都能够代理真实对象,并且代理对象内部包含了真实对象的引用,所以它可以操作真实对象,同时也可以附加其他的操作,相当于对真实对象进行封装。
RealSubject:真实对象,是我们最终要引用的对象。

6.适配器模式(结构型设计模式)
适配器模式是指把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

优点:
更好的复用性,系统需要使用现有的类,而此类的接口不符合系统的需要时,通过适配器模式就可以让功能得到复用;
更好的扩展性,实现适配器功能时,可以调用自己开发的功能,从而自然地扩展系统的功能;

缺点:
过多的使用适配器,会让系统非常乱,明明看到调用的是A接口,其实内部被适配成了B接口的实现

场景
ListView、RecyclerView的adapter
Retrofit中将okhttp3.Call转变成为 retroift中的Call

目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
需要适配的类(Adaptee):需要适配的类或适配者类。
适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。

7.观察者模式(行为型设计模式)
对象间一种一对多的依赖关系,使得每当一个对象改变状态时,则所有依赖于它的对象都会得到通知并被自动更新

优点:
观察者和被观察者之间是抽象耦合,应对业务变化;
增强系统灵活性、可扩展性;

缺点:
程序中包括一个被观察者,多个观察者对象,消息通知是遍历执行的,一个观察者卡顿,会影响整体的执行效率,这时候可以考虑采用异步的方式。
可能会引起多余的数据通知。

场景
BroadcastReceiver广播的注册订阅发送
RxJava

LiveDataBus​​新的消息总线框架,并进行了二次封装

Subject:抽象主题(被观察者),每一个主题可以有多个观察者,并将所有观察者对象的引用保存在一个集合里,被观察者提供一个接口,可以增加和删除观察者角色
ConcreteSubject:具体主题,将有关状态存入具体观察者对象,在主题发生改变时,给所有的观察者发出通知
Observer:抽象观察者,为所有的具体观察者定义一个更新接口,该接口的作用是在收到主题的通知时能够及时的更新自己
ConcreteObserver:具体观察者,实现抽象观察者角色定义的更新接口,以便使本身的状态与主题状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。

8.责任链模式(行为型设计模式)
使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。
将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止

优点:
可以对请求者和处理者关系解耦,提高代码的灵活性。

缺点:
需要对链中请求处理者进行遍历,如果处理者太多,会影响性能。

场景
View事件分发流程
OkHttp发起网络请求拦截器

工作流的处理,比如需求审批

(1)Handler:抽象处理者,定义了一个处理请求的方法。所有的处理者都必须实现该抽象类。
(2)ConcreteHandler:具体处理者,处理它所负责的请求,同时也可以访问它的后继者,如果它能够处理该请求则处理,否则将请求传递到它的后继者。
(3)Client: 客户类

9.策略模式(行为型设计模式)
定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换

优点:
结构清晰明了、使用简单直观;
耦合度较低,扩展方便;
操作封装彻底,数据更为安全;

缺点:
随着策略的增加,子类也变得繁多。

场景
属性动画时间插值器–匀速动画,加速减速插值器(起始加速,结尾减速),减速插值器(减速动画)
Glide磁盘缓存策略

支付功能多种实现方式,比如微信支付、支付宝支付、一网通支付。再比如实现分享时多种策略,可以分享到QQ、微信、微博等社交平台。
请求网络数据时在界面中涉及到的几种状态:数据为空、加载中、数据异常、数据为空、请求成功有数据

(1)环境类(Context):通过 ConcreteStrategy 具体策略类来配置,持有 Strategy 对象并维护对Strategy 对象的引用。可定义一个接口来让 Strategy 访问它的数据。
(2)抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy 定义的算法。
(3)具体策略类(ConcreteStrategy): Strategy 接口的具体算法。

10.模板模式(行为型设计模式)
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤;

优点:
封装不变部分,扩展可变部分;
提供共用部分代码,便于维护;

缺点:
每个不同的实现都需要定义一个子类,会导致类的个数增加,系统更加庞大。

场景
Activity生命周期
View绘制

BaseActivity 的封装

抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。
具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值