JAVA进阶--设计模式
java设计模式
设计模式---固定的模式 每种模式是来解决某一类问题。
一.什么是设计模式
前辈们在长期的开发过程中,针对一些重复出现的问题进行总结,优化,最终总结来的经验.
二.为什么学习设计模式
学习好的设计经验,可以:
提高我们的编程维能力,是的设计更加标准化,
提高程序代码的复用性,可扩展性,灵活性....
提高阅读源码的能力
在大型项目中,在新添加功能的时候,最好不要影响之前的代码.
三.UML建模语言
统一建模语言(Unified Modeling Language,UML) 在软件设计之初,需要通过uml建模语言来分析和设计软件中需要的类与类(接口)之间关系, 以静态图形的方式进行表达, 这个图形成为类图(uml类图).
一般情况下都是架构级别的开发人员才会使用.
1.类图中要素:
简单类图:
①类
类是指具有相同属性、方法和关系的对象的抽象,封装了数据和行为,具有封装性、继承 性和多态性等三大特性.
(1) 类名(Name)是一个字符串
(2) 属性(Attribute)是指类的特性,即类的成员变量
(3) 操作(Operations)是类的任意一个实例对象都可以使用的行为,是类的成员方法
[可见性]名称(参数列表)[:返回类型]
②接口
接口(Interface)是一种特殊的类,它具有类的结构但不可被实例化,只可以被子类实现。
2.类之间的关系
①继承关系
父类与子类之间的关系,是一种继承关系,是 is-a 的关系(xx是xx)。
{ 类继承类 ,接口继承接口 }
②实现关系
实现关系是接口与实现类之间的关系--类实现了接口
③依赖关系
use-a关系 在xx中用到xx
在一个类中的方法里面,使用到了另一个类, 关系弱,具有临时性(方法运行结束,关系就结束了)
④关联关系
把B类作为A的成员变量 has-a xx有xx
关联关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系
关联又可以分为单向关联,双向关联,自关联
单向关联
双向关联
自关联
⑤聚合关系
也是关联的一种, 是整体和部分的关系,列如学校和老师支之间的关系,学校如果不存在了,
老师可以独立的存在.
⑥组合关系
是一种更强烈的关联关系, 例如头和嘴的关系, 头不存在了,嘴也就不存在了.
四.面向对象设计原则
学习面向对象设计原则好处
在复杂的程序设计时,如果没有好的设计,在后期扩展功能时就很麻烦.
所以好的设计原则,可以提升程序设计的水平(可复用性,可维护性/可扩展性
1.单一职责
一个类只负责一件事情.
2.开闭原则
开闭原则 即 对修改关闭,对扩展开放 在增加新功能时,通过扩展一个新类来实现功能,尽量 少的修改之前的代码
3.依赖倒置原则
编程实现不应该依赖于底层实现(实现类),而是应该依赖于上层的抽象,
先根据实际情况,进行分析,设计出接口/抽象类,在抽象层中定义好功能, 底层实现根据上层 的定义来具体实现即可
4.接口隔离
把接口粒度更小,把同一类 的功能定义在一个接口中, 不要把所有的功能定义在一个接口 中,这样实现类会继承过来一些不需要的功能过来
5.组合/聚合复用原则
如果在B类中需要复用A类中的某些方法, 除了让B类继承A类之外, 还可以在B类中关联A 类, 在B类中依赖A类.
只是为了复用某几个方法,使用继承的代价要高一些,因为B类会把A类中所有的功能继承 过来,以及A类的父类
6.里氏替换原则
在使用继承时, 在使用父类时,如果将其换成子类,也要保证功能不会受影响.
当子类继承父类后,重写了父类中的方法, 这时如果把父类替换成子类,那么会影响父类原 来的功能.
如何避免: 如果子类需要重写父类中的方法,那么将父类定义为抽象类
7.迪米特原则
只跟朋友联系,不和陌生人说话
举例: 明星 不直接与 粉丝,公司进行接触, 让明星,粉丝,公司通过经济人产生联系
五.常用设计模式
1.单例模式
单例模式解决一个类在一个项目中只能创建一个对象.
单例对象只能由单例类自己创建
对外提供一个可获得单例对象的方法
单例模式分为:饿汉式单例,懒汉式单例
饿汉式单例:
好处: 不存在线程安全问题
不足: 启动时创建对象,启动时间会变长.
懒汉式单例:
在第一次获取单例对象时才创建
不足: 会存在线程安全问题
package com.ffyc.javapro.oop.design.singleton.demo2;import com.ffyc.javapro.oop.design.singleton.demo1.Window;/*懒汉式单例: 在第一次获取单例对象时才创建不足: 会存在线程安全问题*/
public class WIndow {/*加volatile主要解决的是禁止指令重排性*/private volatile static WIndow window = null;private WIndow(){}/*双重检索+volatile 的懒汉式单例*/public static WIndow getWindow(){if(window==null){synchronized (WIndow.class){if(window==null){window = new WIndow();}}}return window;}/*虽然解决了线程安全问题,但是效率低public synchronized static WIndow getWindow(){if(window==null){window = new WIndow();}return window;}*//*会存在线程安全问题public static WIndow getWindow(){if(window==null){window = new WIndow();}return window;}*/}
系统中的Runtime类 就是一个饿汉式单例类
双重检索
进入方法先检查实例是否存在,存在则直接返回,如果不存在才会进入代码, 此时再次检查是否存在实例,如果不存在,则在同步状态下进行实例创建,既保证了懒加载,又保证了高性能.
/*双重检索+volatile 的懒汉式单例*/public static WIndow getWindow(){if(window==null){synchronized (WIndow.class){if(window==null){window = new WIndow();}}}return window;}
2.工厂模式
工程模式解决如何大量的创建对象
工厂模式分为工厂方法模式和抽象工厂模式
简单工厂引入
简单工厂一个工厂创建一类对象,需要根据传入的参数判断创建那个具体类的对象,
不满足开闭原则, 添加新类型时,需要修改工厂代码
工厂方法
为每一个具体的产品提供一个专门的工厂,专门负责生产这一具体产品,
满足了开闭原则,增加一个产品,就增加一个具体产品对应的工厂.
抽象工厂
抽象工厂模式,解决了一个具体工厂只能造一个具体产品缺陷,
抽象工厂中,一个工厂可以创造同一个公司下多个不同类型的产品
3.模版方法模式
定义一个模版类,在模版类中可以定义多个模版方法, 在模版方法中,把几个固定流程方法进行调用,在这些方法中,有的实现都一样,在模版类中直接实现,有的方法实现有不同,把这些方法定义抽象的,在子类中去实现,最终不同的功能使用不同的子类对象来调用模版方法,完成一个功能.
优点:
①提高代码的复用性,把相同的功能在模版类中实现,不同的功能放在子类中实现.
②在父类中的模版方法中,调用不同子类中的方法,实现反向控制, 增加新功能,扩展不同的子类即可,满足了开闭原则
不足:
①扩展功能需要添加子类,功能多了子类也就多了,
②在父类中反向调用子类中方法,增加了代码的阅读难度.
4.策略模式
结构:
①抽象策略类:一个抽象角色,由一个接口或抽象类实现。给出所有的具体策略类所需的接口。
②具体策略类:实现了抽象策略定义的接口,提供具体的算法实现或行 为。
③环境类:持有一个策略类的引用,最终给客户端调用
使用:
先抽象,把要做的这件事情进行抽象,不同做法,使用不同的子类,在使用时,只需要传入不同的子类即可.(解决了在不同内容之间选择的问题)
5.代理模式
为目标对象(汽车厂, save(),delete()),提供代理对象, 让客户通过代理对象对目标进行访问,
好处: ①不让客户直接与目标对象直接交互
②代理对象可以为目标对象添加额外的扩展功能. 而且不需要修改目标对象
静态代理
静态代理,一个代理类只能为某个接口/抽象类的子类进行代理,
如果需要为其他接口/抽象类的子类进行代理,那么就需要重新创建一个代理类.
动态代理
动态代理解决了一个代理类只能代理某个接口的子类,
可以为目标类动态生成代理对象,可以为任何目标类实现代理
动态代理有两种实现方式:
①jdk代理:
底层是通过反射机制实现, 要求目标类必须实现一个接口
②spring中的cglib代理:
底层采用字节码生成技术,动态为目标类生成一个子类,在调用目标类方法,采用方法拦截技术,在调用方法之前和之后添加额外扩展功能, 目标类可以不实现接口