Java设计模式

Java设计模式

设计模式是一套被反复使用、多数人知晓的、代码设计经验的总结。描述了在软件设计过程中一些不断重复发生的问题,以及解决方案。也就是说它是解决特定问题的一系列套路,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码可读性和代码可靠性。

学习设计模式的意义

设计模式的本质是面向对象设计原则的实际运用,是对累的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优点:

  1. 可以提高程序员的思维能力、编程能力和设计能力。
  2. 使程序设计更加标准化、代码编制更加工程化,大大提高开发效率。
  3. 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。

根据模式是用来完成什么工作划分,这种方式可以分为创建型模式、结构型模式和行为型模式3种。

==创建型模式:==用于描述“怎么创建对象”,它的主要特点是“将对象的创建与使用分离”。提供了单例、原型、工厂方法、抽象工厂、建造者5种创建型模式。

==结构型模式:==用于描述如何将类或对象按某种布局组成更大的结构,提供了代理、适配器、桥接、装饰、外观、享元、组合7种结构型模式。

==行为型模式:==用于描述类或对象之间怎样互相协作共同完成单个对象都无法单独完成任务,以及怎样分配职责。提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器11种行为型模式。

23种设计模式介绍

  1. 单例模式:某个类自能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
  2. 原型模式:将一个对象作为原型,通过对其进行复制克隆出多个和实例类似的新实例。
  3. 工厂方法模式:定义一个用于创建产品的接口,由子类决定生产什么产品。
  4. 抽象工厂模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
  5. 建造者模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。
  6. 代理模式:为某种对象提供一种代理以控制对该对象的访问。即客户端通过代理间接访问该对象,从而限制、增强或修改该对象的一些特性。
  7. 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
  8. 桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
  9. 装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。
  10. 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
  11. 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。
  12. 组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。
  13. 模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
  14. 策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。
  15. 命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。
  16. 职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。
  17. 状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。
  18. 观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。
  19. 中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。
  20. 迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
  21. 访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。
  22. 备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。
  23. 解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

常用设计模式

单例模式

在某些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。例如:Windows只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容不一致等错误。

特点:

  1. 单例类只有一个实例对象。
  2. 该单例对象必须由单例类自行创建。
  3. 单例类对外提供一个访问该单例的全局访问点。

单例模式的结构

单例类:包含一个实例且能自行创建这个实例的类。

访问类:使用单例的类。结构如图所示:

image-20210720190436526

Singleton模式通常有两种实现形式:

  1. 懒汉式单例
public class student{
	private static student stu;
	private student(){}
	public static student getStu(){
		if(stu == null){
			stu = new student();
		}
		return stu;
	}
}

该模式的特点是类加载时没有生成单例,只有当第一次调用getStu()方法时,才会去创建这个单例。

  1. 饿汉式单例
public class student{
	private static student stu = new student();
	private student(){}
	public static student getStu(){
		return stu;
	}
}

该模式的特点是类一旦加载就创建一个单例,保证在调用getStu()方法之前单例已经存在。

工厂模式

定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类中。这满足创建型模式中所要求的的“创建于使用相分离”的特点。

按实际业务场景划分,工厂模式有3种不同的实现方式,分别是简单工厂模式工厂方法模式抽象工厂模式

简单工厂

我们把被创建出来的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。

在简单工厂模式中创建实例的方法通常为静态方法,因此简单工厂模式又叫做“静态工厂方法模式”。

简单工厂模式每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度,违背了“开闭原则”。

简单工厂模式的主要角色如下:

简单工厂:是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。

抽象产品:是简单工厂创建的所有对象的父类,负责描述所有市里共有的公共接口。

具体产品:是简单模式的创建目标。

结构如下:

image-20210720193019235

代理模式

在某些情况下,一个客户不能或不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。如:购买手机不需要去工厂购买,可以通过手机店或者网上进行购买。

代理模式的主要优点:

  1. 代理模式在客户端与目标之间起到一个中介作用保护目标对象的作用。
  2. 代理对象可以扩展目标对象的功能。
  3. 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度

模式的结构:

  1. 抽象主题类:通过接口或抽象类申明真实主题和代理对象实现的业务方法。
  2. 真实主题类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  3. 代理类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

结构如图:

image-20210720194059588

代理实现可以分为静态代理动态代理

静态代理

静态代理模式的特点:代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点:每个代理类都必须实现一遍委托类(真实主题类)的接口。如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应着一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。

动态代理

动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等,动态代理分为jdk动态代理和cglib动态代理。

jdk代理

要求:被代理类最少实现一个接口

动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。

步骤如下:

  1. 编写一个委托类的接口,即静态代理。
  2. 实现一个真正的委托类,即静态代理。
  3. 创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法。
  4. 在测试类中生成动态代理对象。

动态代理总结:虽然相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。但是还是有一点点小遗憾,就是它始终无法摆脱仅支持interface代理的束缚,因为它的设计注定了这个遗憾。回想一下这些动态生成的代理类的继承关系图,它们以及注定有一个共同的父类叫Proxy。

Cglib代理

要求:该代理类不能是最终类(不能被final修饰)

JDK实现代理需要通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢?这里就需要Cglib了。

Cglib采用了非常底层的字节码技术,其原理是通过字节码技术为目标类创建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势植入横切逻辑。但因为采用了继承,所以不能对final修饰的类进行代理。

JDK动态代理与Cglib动态代理均是实现Spring AOP的基础。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值