java设计模式

目录

一.创建型:

1.单例模式

1.饿汉式(急切式)

2. 懒汉式

2.工厂模式

简单工厂模式(不属于GOF的23种经典设计模式) :

工厂方法模式:

3.抽象工厂模式

4.原型模式

二、结构型

1.代理模式

1.静态代理:

2.动态代理:

2.适配器模式

三、行为型

1. 模板方法模式

2.策略模式

3.观察者模式


设计模式本质上是面向对象设计原则的实际运用,是对类的封装性、继承性、多态性以及类的关联关系和组合关系的充分理解。

最早诞生在建筑模式,后来引用到软件领域,经过前辈的代码设计的经验,总结的一套可以反复使用的设计模式。

java中设计模式共23种

分为3大类

一.创建型:

如何创建对象

1.单例模式

解决一个类在一个程序中保证只能创建一个对象

单例模式只创建一个对象,这个对象由单例类自己创建,并向外提供访问方法。

实现方式有两种:

1.饿汉式(急切式)

立即创建,类加载时就创建好,没有线程安全问题

2. 懒汉式

在类加载时,并不创建单例对象,在第一次获取单例对象时才创建

存在线程安全问题,如下:可能出现两个线程同时进入创建两个对象。

给方法添加锁后,虽然能解决线程安全问题,但是并发访问的效率低,

解决方法:

双重检索+volatile

例如: 

 static volatile WindowDemo windowDemo = null;

 

 Runtime类就是一个单例类,可查看源码:

2.工厂模式

工厂类,负责生产某一类产品,同一类产品,将创建对象和使用对象分离。

在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说,工厂模式最大的优点就是:解耦

简单工厂模式(不属于GOF23种经典设计模式)

        简单工厂违背了开闭原则

例如Car工厂:加一个类型,工厂中的代码就需要修改。

使用场景:所有产品子类都有一个父类(或接口),属于同一个产品系列,产品子类比较少,创建操作比较简单。

工厂方法模式:

工厂方法,对工厂进行抽象,一个抽象的产品对应一个抽象的工厂

一个具体的产品,对应一个具体的工厂,一个具体的工厂负责生产一个具体的产品

需要扩展新产品时,只需添加新的具体产品和生产产品的工厂,不用修改原来的工厂,符合开闭原则。

结构:

抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂
方法来创建产品。

具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

抽象产品(product):定义了产品的规范,描述了产品的主要特性和功能。

具体产品(concreteproduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间--对应。 

3.抽象工厂模式

抽象工厂是生产一系列产品(某个公司的一系列产品:小米手机,小米汽车;)

在抽象的工厂中定义不同的产品。

具体的工厂负责生产一个公司的一系列产品。

优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

4.原型模式

在开发过程中,需要创建多个数据相同的对象,每次New创建开销比较大,

使用对象克隆,以先创建出来的原型对象为模板。

使用对象克隆,以先创建出来的原型对象为模板进行对象复制,提高了创建效率

例如: 简历,奖状

对象的创建非常复杂,可以使用原型模式快捷的创建对象。
性能和安全要求比较高。

 示例:

二、结构型

1.代理模式

目标对象的代理者

例如:汽车厂买汽车,需要4s店代理去卖,可以帮助客户上牌,买保险,售后等其他服务;

帮助目标(实际的执行者),扩展目标对象的功能,而不修改目标对象代码。

优点:

将目标与添加的功能相分离,保护了目标对象,

降低了耦合度,增加新的功能,不需要修改目标对象。

代理模式的结构:

抽象主题:通过接口或抽象类声明真实主题和代理对象实现的业务方法。

真实主题:实现了抽象主题中的具体业务,是代理对象 所代表的真实对象,是最终要引用的对象。

代理类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

代理可以分为静态代理和动态代理:

1.静态代理:

一个代理类可以对某一类的目标提供代理,满足开闭原则(添加一类目标时,可以扩展添加一个新的代理类)

优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。

缺点:一个代理类只能代理一个接口,工作量太大;代理类是运行前编码已经完成的;必须先有接口,再有代理;接口一旦发生变量,代理类也要修改。

2.动态代理:

在运行时可以动态的创建代理类,分为jdk、cglib

jdk代理:

创建一个代理对象的生成器,实现InvocationHandler,重写invoke方法,此方法会被代理动态调 用。

代理对象在运行时,被动态的创建,可以代理任意的目标对象,必须实现一个接口,在生成代理对象时,需要通过接口来获取目标对象的信息。

底层使用的是反射机制

Java中提供了一个动态代理类 Proxy,Proxy并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法 (newProxyInstance方法)来获取代理对象。

例如:

因此, ProxyFactory 不是代理模式中所说的代理类,而代理类是程序在运行过程中动态的在内存中生成的类。 代理类( $Proxy0 )实现了 SellTickets 。这也就印证了我们之前说的真实类和代理类实
现同样的接口。 代理类($Proxy0 )将我们提供了的匿名内部类对象传递给了父类。

Cglib代理:    

实现时,不需要目标类去实现接口,采用动态字节码生成技术,为我们的目标类生成一个子类对象,当调用方法时,对方法进行拦截,调用目标类方法。

要求目标类不能是final修饰,方法也不能是final修饰的,和static修饰的。

CGLIB 是第三方提供的包,所以需要引入 jar 包的坐标:
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

spring框架中两种代理生成机制都实现了;可以根据目标是否实现接口自动选择生成代理对象的方式,SpringAOP中用到两种动态代理方式,如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP,如果目标对象没有实现接口,则会采用CGLIB动态代理。

JDK动态代理和CGLIB动态代理的区别?(面试高频)

  •  JDK动态代理是通过反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用nvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来通过修改其字节码生成子类来处理。
  •  JDK动态代理的核心是实现InvocationHandler接口,使用invoke()方法进行面向切面的处理,调用相应的通知。cglib动态代理核心是实现Methodlnterceptor接口,使用intercept()方法进行面向切面的处理,调用相应的通知。
  •  JDK动态代理只能代理实现实现接口的类,不能代理没有实现接口的类。CGLIB动态代理是针对类来实现代理的,对指定的目标类生成一个子类,并覆盖其中方法实现增强,不能对final修饰的类进行代理。
  • 在JDK1.6之前,CGLIB动态代理的效率比IDK动态代理要高,JDK1.6开始对IDK动态代理优化后JDK动态代理的效率比CGLIB动态代理要高,但当大量调用的时候,JDK1.6和IDK1.7的效率比CGLIB动态代理效率低一些,到DK1.8,JDK动态代理的效率比CGLIB动态代理高。

2.适配器模式

将一个类的接 口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能 一起工作。
适配器模式分为类适配器模式和对象适配器模式,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

结构:

目标( Target )接口:当前系统业务所期待的接口,它可以是抽象类或接口。
适配者( Adaptee )类:它是被访问和适配的现存组件库中的组件接口。
适配器( Adapter )类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

三、行为型

行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单 个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。

1. 模板方法模式

在程序开发中,有些实现步骤流程是固定的,可以抽取父类,在父类中实现各个步骤,在父类中定义一个流程控制方法,在此方法中按照步骤调用执行。

可以将某个容易发生变化的步骤定义为抽象方法,针对不同的情况,可以扩展一个子类实现抽象的方法,最终是父类调用子类实现的方法。  

优点:
1.提高代码复用性
将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。
2.实现了反向控制
通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制 ,并
符合 开闭原则
使用场景:
算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分
抽象出来,供子类实现。
需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
例如:
InputStream 类就使用了模板方法模式。在 InputStream 类中定义了多个 read() 方法
无参的 read() 方法是抽象方法,要求子类必须实现。而 read(byte b[])
方法调用了 read(byte b[], int off, int len) 方法,所以在此处重点看的方法是带三个参数的 方法。
InputStream 父类中已经定义好了读取一个字节数组数据的方法是每次读取一个字节,并将其存储到数组的第一个索引位置,读取len 个字节数据。具体如何读取一个字节数据呢?由子类实 现。

2.策略模式

可以将同一种功能不同实现细节先抽取一个抽象接口/抽象类,

然后把不同的实现让子类继承实现,

最中选择时,只需要选择不同的子类实现,将不同实现封装不同的子类中。

使用场景:一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。

例如:Arrays中的sort()方法

3.观察者模式

又称为“发布-订阅”模式,

例如“微信公众号”,微信用户就是观察者,微信公众号是被观察者,有多个微信用户关注了这个公众号。

优点
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
被观察者发送通知,所有注册的观察者都会收到信息【可以实现广播机制】
缺点
如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时
如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃

 使用场景:

对象间存在一对多关系,一个对象的状态发生改变会影响其他对象;
当一个抽象模型有两个方面,其中一个方面依赖于另一方面时。
例如: Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模 式,只要实现它们的子类就可以编写观察者模式实例。
  • 37
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小俱的一步步

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值