Java设计模式(java design patterns)
java设计模式
设计模式---固定的模式 每种模式是来解决某一类问题
什么是设计模式
在长期开发过程中,针对某一些重复出现的问题进行总结,优化,最终总结出来的经验
为什么学习设计模式
学习好的设计经验可以:
提高编程思维能力,使设计更加标准化.
提高程序代码的复用性,可扩展性,灵活性...
提高阅读源码的能力
在大型项目中,在新添加功能的时候,最好不要影响之前的代码
UML建模语言
类:

接口:
简单类图:
类之间关系
1.继承关系
类继承类
接口继承接口
is-a关系 xx是xx
2.实现关系
类实现接口
3.依赖关系
use-a关系 在xx中用到xx
在一个类中的方法里面,使用到了另一个类,关系弱,具有临时性(方法运行结束后,关系也就结束)
4.关联关系
把B类作为A的成员变量
has-a xx有xx
人关联手机
单项关联
双向关联
自关联
关联关系根据关系的强弱又分为:
聚合关系:
也是关联的一种,是整体和部分的关系
eg:学校与老师的关系,学校不存在,老师也可独立存在
组合关系
是一种更强烈的关联关系
eg:头和嘴的关系,头不存在,嘴也就不存在
面向对象设计原则
面向对象?
面向对象是一种编程思想
面向过程是关注实现的步骤,每个步骤定义一个函数,调用函数执行即可
面向对象关注的是谁(对象)来执行,把具有相同属性和行为的一类事物(对象)进行抽象成类,然后通过类实例化出一个个具体的对象,使用的具体的对象
万事万物(现实存在)皆为对象
类包含:
成员变量(属性)名词
成员方法(行为)动词
构造方法(用来为刚创建的对象的成员进行初始化赋值)
面向对象三大特征
封装
误区:把封装理解为包装
使用访问权限修饰符(eg: private)把类中某些成员隐藏起来,不让直接访问,为私有成员提高特定的公共方法进行访问
继承
子继承父
可以继承父类中成员(功能),提高代码的复用性
子类可以对父类的方法进行重写
多态
同一事物,再不同时刻表现不同的状态
父类的引用指向子类地下
Public void feedAnimal(Animal animal){animal.eat(); }
多态提高程序设计的扩展性,(在新增功能适合,只添加新类,尽量可能少的修改原来的代码)满足开闭原则,对修改关闭
Object valueOf();
抽象类和接口
抽象类:被abstract修饰的类
一个不完整的类(里面包含抽象方法)就可以定义抽象类,一般在类体系结构的顶层类,大多都是抽象类
特点: 不能实例化对象 其他功能和正常类一样
接口: 接口可以理解为一种特殊的抽象
接口重点在于定义功能(抽象方法),不能定义成员变量,即使定义也只能定义静态常量
接口同样不能被实例化对象,由子类实现,重写其中的抽象方法
什么时候用抽象类,什么适合用接口?
当还需要定义成员变量,构造方法,具体方法时,应该使用抽象类
当只定义功能时,使用接口
学习面向对象设计原则的好处
在复杂的程序设计时,如果没有好的设计,在后期扩展功能时就很麻烦.
所以好的设计原则可以提升程序设计的水平(可复用,可维护,可扩展)
单一职责原则
一个类只负责一件事情
开闭原则
开闭原则即 对修改关闭,对扩展开放 :在增加新功能时,通过扩展一个新类来实现功能,尽量少的修改之前的代码
接口隔离原则
把接口粒度更小,把同一类的功能定义在一个接口中,不要把所有的功能定义在一个接口中,这样实现类会继承过来一些不需要的功能过来
依赖倒置原则
编程实现不应该依赖与=于底层实现(实现类),而是应该依赖于上层的抽象,
先根据实际情况,进行分析,设计出接口/抽象类,在抽象层中定义好功能,底层实现根据上层的定义来具体实现.
组合/聚合复用原则
如果在B类中需要复用A类中的某些方法,除了让B类继承A类之外,还可以在
B类中关联A类,在B类中依赖A类,
只是为了复用某几个方法,使用继承的代价要高一些,因为B类会把A类中所有的功能继承过来,以及A类的父类
里氏替换原则
在使用继承时,在使用父类时,如果将其换成子类,也要保证功能不会受影响,
当子类继承父类后,重写了父类中的方法,这是如果把父类替换成子类,那么会影响父类原来的功能
如何避免:如果子类需要重写父类中的方法,那么将父类定义为抽象类
迪米特原则
"只和朋友联系,不和陌生人说话"
eg:明星 不直接与 粉丝,公司进行接触,让 明星,粉丝公司,通过经纪人产生联系
单例模式
单例模式解决一个类在一个项目中只能创建一个对象
1.单例对象只能由单例类自己创建
2.对外提提供一个可获得单例对象的方法
单例模式分为:
饿汉式单例(急切式单例)
类加载的时候:就把单例对象创建出来
public class HungrySinglet {private static HungrySinglet hungrySinglet=new HungrySinglet();public static HungrySinglet getHungrySinglet(){return hungrySinglet;}private HungrySinglet(){}
}
懒汉式单例:
public class LazySinglet {private static LazySinglet lazySinglet;private LazySinglet() {}public static synchronized LazySinglet getLazySinglet() {if (lazySinglet == null) {lazySinglet = new LazySinglet();}return lazySinglet;}
}//--------------------------------------------------------------------
//双重检索
public class LazySinglet {private static volatile LazySinglet lazySinglet;private LazySinglet() {}public static LazySinglet getLazySinglet() {if (lazySinglet == null) {synchronized (LazySinglet.class) {if (lazySinglet == null) {lazySinglet = new LazySinglet();}}}return lazySinglet;}
}
工厂模式
工厂模式解决如何大量的创建对象
工厂模式分为工厂方法模式二号抽象工厂模式
简单工厂引入
简单工厂一个工厂创建一类对象,需要根据传入的参数判断创建哪个具体类的对象
不满足开闭原则,添加新类型时,需要修改工厂代码
工厂方法:
为每一个具体的产品提供一个专门的工厂,专门负责生产这一具体产品,
满足了开闭原则,增加一个产品就增加一个具体产品对应的工厂
抽象工厂
抽象工厂模式,解决了一个具体工厂只能造一个具体产品缺陷
抽像工厂中,一个工厂可以创造同一个公司下多个不同类型的产品
模板方法模式
定义一个模板类,在模板类中可以定义多个模板方法,在模板方法中,把几个固定流程的方法进行调用,在这些具体方法中,有的实现都一样,在模板类中直接实现,优先方法有不同,把这些方法定义抽象的,在子类中实现,最终不同功能使用不同的子类对象来调用模板方法,完成一个功能
优点:提高代码的复用性,把相同的功能在模板类中实现,不同的功能放在子类中实现
在父类中的模板方法中,调用不同子类中的方法,实现的了反向控制,增加新功能,扩展不同的子类即可,满足了开闭原则
缺点:扩展功能需要添加子类,功能多了子类就多了
在父类中反向调用子类中的方法,增加了代码的阅读难度
策略模式
解决了在不同内容之间选择的问题
先抽象,把要做的这件事情进行抽象,
不同的做法使用不同的子类
在使用时,只需要不同的子类即可
代理模式
为目标对象(汽车厂,save()),提供代理对象,让客户通过代理对象对目标进行访问
好处:不让客户直接与目标对象直接交互
代理对象可以为目标对象添加额外的扩展功能,而且不需要修改目标对象
/* 得理解代码 */
静态代理
静态代理,一个代理类只能为某一个接口/抽象类的子类进行代理
如果需要为其他接口/抽象类的子类进行代理,那么就需要重新创建一个代理类
动态代理
动态代理解决了一个代理类只能代理某个接口的子类
可以为目标类动态生成代理对象,可以为任何目标类实现代理
动态代理有两种实现方式:
jdk代理:
底层是通过反射机制实现,要求目标类必须实现一个接口
spring中的cglib代理:
底层采用字节码生成计数,动态为目标类生成一个子类,在调用目标类方法,采用方法拦截技术,在调用方法之前和之后添加额外扩展功能,目标类可以不实现接口