设计模式详解:从基础原则到 Java 经典模式
java的设计模式
设计模式---固定的模式 每种模式是用来解决某一类问题
1.设计模式
学习好的设计经验,可以:
提高我们的编程思维能力,是的设计更加标准化,
提高程序代码的复用性,可扩展性,灵活性....
提高阅读源码的能力
在大型项目中,在新添加功能的时候,最好不要影响之前的代码.
2.UML建模语言
2.1类与接口
统一建模语言(Unified Modeling Language,UML) 在软件设计之初,需要通过uml建模语言来分析和设计软件中需要的类与类(接口)之间关系, 以静态图形的方式进行表达, 这个图形成为类图(uml类图).
一般情况下都是架构级别的开发人员才会使用.
类图中要素:
类:

接口:

简单的类图:

2.2类之间的关系
1.继承关系
类继承类
接口继承接口
is-a关系 xx是xx

2.实现关系
类实现接口

3.依赖关系
use-a关系 在xx中用到xx
在一个类中的方法里面,使用到了另一个类, 关系弱,具有临时性(方法运行结束,关系就结束了)

4.关联关系
把B类作为A的成员变量
has-a xx有xx
人关联手机
单向关联
双向关联
自关联
关联关系根据关系的强弱又分为:
1.聚合关系
也是关联的一种, 是整体和部分的关系,列如学校和老师支之间的关系,学校如果不存在了,
老师可以独立的存在

2.组合关系
是一种更强烈的关联关系, 例如头和嘴的关系, 头不存在了,嘴也就不存在了.

3.面向对象设计原则
3.1面向对象:
面向对象是一种编程思想, 面向过程是关注实现的步骤,每个步骤定义一个函数,调用函数执行即可.
面向对象关注的是谁(对象)来执行,把具有相同属性和行为的一类事物(对象)进行抽象成类,
然后再通过类实例化出一个个具体的对象,使用的具体的对象.
类包含:
成员变量(属性) 名词
成员方法(行为) 动词
构造方法(用来为刚创建的对象的成员进行初始化赋值)
3.2面向对象特征
封装:
误区:把封装理解为包装了
使用访问权限修饰符把类中某些成员隐藏起来,不让直接访问,为私有成员提供特定的公共方法进行访问
private String name;
继承:
子继承父
可以继承父类中成员(功能),提高代码代码的复用性
子类可以对父类方法进行重写
多态:
同一个事物,在不同时刻表现不同的状态
父类的引用指向子类对象
public void feedAnimal(Animal animal){
animal.eat();
}
多态提高程序设计的扩展性(在新增功能时候,只添加新类,尽可能少的修改原来的代码), 满足开闭原则,对修改关闭
抽象类:被abstract修饰的类
一个不完整的类(里面包含抽象方法)就可以定义抽象类,一般在类体系结构的顶层类,大多都是抽象类.
抽象类特点:
不能实例化对象.
其他功能和正常类一样
接口:
接口可以理解为是一种特殊的抽象
接口重点在于定义功能(抽象方法), 不能定义成员变量, 即使定义也只能定义静态常量
接口同样不能被实例化对象, 由子类实现,重写其中的抽象方法.
什么时候用抽象类,什么是用接口?
当还需要定义成员变量,构造方法,具体方法时,应该使用抽象类
当只定义功能时,使用接口.
4.面向对象设计原则
在复杂的程序设计时,如果没有好的设计,在后期扩展功能时就很麻烦.
所以好的设计原则,可以提升程序设计的水平(可复用性,可维护性/可扩展性
4.1单一职责
一个类只负责一件事情.
4.2开闭原则
开闭原则 即 对修改关闭,对扩展开放 在增加新功能时,通过扩展一个新类来实现功能,尽量少的修改之前的代码
4.3接口隔离
把接口粒度更小,把同一类 的功能定义在一个接口中, 不要把所有的功能定义在一个接口中,这样实现类会继承过来一些不需要的功能过来
4.4依赖倒置原则
编程实现不应该依赖于底层实现(实现类),而是应该依赖于上层的抽象,
先根据实际情况,进行分析,设计出接口/抽象类,在抽象层中定义好功能, 底层实现根据上层的定义来具体实现即可.
4.5组合聚合复用原则
如果在B类中需要复用A类中的某些方法, 除了让B类继承A类之外, 还可以在B类中关联A类, 在B类中依赖A类.
只是为了复用某几个方法,使用继承的代价要高一些,因为B类会把A类中所有的功能继承过来,以及A类的父类
4.6里氏替换原则
在使用继承时, 在使用父类时,如果将其换成子类,也要保证功能不会受影响.
当子类继承父类后,重写了父类中的方法, 这时如果把父类替换成子类,那么会影响父类原来的功能.
如何避免: 如果子类需要重写父类中的方法,那么将父类定义为抽象类
4.7迪米特原则
只跟朋友联系,不和陌生人说话
举例: 明星 不直接与 粉丝,公司进行接触, 让明星,粉丝,公司通过经济人产生联系
5.单例模式
单例模式解决一个类在一个项目中只能创建一个对象.
1. 单例对象只能由单例类自己创建
2. 对外提供一个可获得单例对象的方法
单例模式分为:
饿汉式单例:
好处: 不存在线程安全问题
不足: 启动时创建对象,启动时间会变长.
/*
饿汉式单例:启动时创建对象,启动时间会变长.
*/
public class WIndow {
private static WIndow window = new WIndow();
private WIndow(){
}
public static WIndow getWindow(){
return 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类 就是一个饿汉式单例类

6.工厂模式
工程模式解决如何大量的创建对象
工厂模式分为工厂方法模式和抽象工厂模式
6.1简单工厂引入
简单工厂一个工厂创建一类对象,需要根据传入的参数判断创建那个具体类的对象,
不满足开闭原则, 添加新类型时,需要修改工厂代码

6.2工厂方法
为每一个具体的产品提供一个专门的工厂,专门负责生产这一具体产品,
满足了开闭原则,增加一个产品,就增加一个具体产品对应的工厂.

6.3抽象工厂
抽象工厂模式,解决了一个具体工厂只能造一个具体产品缺陷,
抽象工厂中,一个工厂可以创造同一个公司下多个不同类型的产品

7.模版方法模式
定义一个模版类,在模版类中可以定义多个模版方法, 在模版方法中,把几个固定流程方法进行
调用,
在这些方法中,有的实现都一样,在模版类中直接实现,有的方法实现有不同,把这些方法定义抽
象的,在子类中去实现,
最终不同的功能使用不同的子类对象来调用模版方法,完成一个功能.
优点: 提高代码的复用性,把相同的功能在模版类中实现,不同的功能放在子类中实现.
在父类中的模版方法中,调用不同子类中的方法,实现反向控制, 增加新功能,扩展不同的子类即可,满
足了开闭原则
不足: 扩展功能需要添加子类,功能多了子类也就多了,
在父类中反向调用子类中方法,增加了代码的阅读难度.
8.策略模式
解决了在不同内容之间选择的问题
先抽象,把要做的这件事情进行抽象,
不同做法,使用不同的子类,
在使用时,只需要传入不同的子类即可.
9.代理模式
为目标对象(汽车厂, save(),delete()),提供代理对象, 让客户通过代理对象对目标进行访问,
好处: 不让客户直接与目标对象直接交互
代理对象可以为目标对象添加额外的扩展功能. 而且不需要修改目标对象
9.1静态代理
静态代理,一个代理类只能为某个接口/抽象类的子类进行代理,
如果需要为其他接口/抽象类的子类进行代理,那么就需要重新创建一个代理类.
9.2动态代理
动态代理解决了一个代理类只能代理某个接口的子类,
可以为目标类动态生成代理对象,可以为任何目标类实现代理
动态代理有两种实现方式:
jdk代理:
底层是通过反射机制实现, 要求目标类必须实现一个接口
package com.ffyc.javapro.oop.design.proxy.dtProxy;
public class PhoneFactory implements SellPhone {
@Override
public void sellPhone() {
System.out.println("手机厂卖手机");
}
}
/*
汽车厂
*/
public class CarFactoryImpl implements SellCar {
@Override
public void sellCar() {
System.out.println("汽车厂卖汽车");
}
}
/*
代理对象的生成器类
*/
public class DynamicProxy implements InvocationHandler {
Object object;//真实对象,接收任何的目标类对象
public DynamicProxy(Object object) {
this.object = object;
}
/*
在代理类中调用目标类中的具体方法,
动态的将代理动态对象,目标类中要调用的方法,及方法中的参数传递过来
Method method 就是动态获取的真正要执行的方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("之前开启事务");
method.invoke(object);//想起反射机制 ,method表示要真正执行的方法
System.out.println("之后提交事务");
return proxy;
}
/*
使用反射机制,生成代理对象的
*/
public Object getProxy(){ //获取目标类的接口
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}
}
/*
抽象操作定义 卖东西
*/
public interface SellCar {
void sellCar();
}
public interface SellPhone {
void sellPhone();
}
package com.ffyc.javapro.oop.design.proxy.dtProxy;
public class Test {
public static void main(String[] args) {
CarFactoryImpl carFactory = new CarFactoryImpl();//创建真实主题
DynamicProxy dtproxy = new DynamicProxy(carFactory);//创建代理对象生成器
//这才是真正的创建动态代理对象 获取目标类所实现的接口
SellCar carfactory = (SellCar)dtproxy.getProxy();
carfactory.sellCar();//使用代理对象调用接口中的方法,获取当前调用的方法,最终调用invoke方法
PhoneFactory phoneFactory = new PhoneFactory();
DynamicProxy dynamicProxy = new DynamicProxy(phoneFactory);
SellPhone sellPhone = (SellPhone) dynamicProxy.getProxy();
sellPhone.sellPhone();
}
}
spring中的cglib代理:
底层采用字节码生成技术,动态为目标类生成一个子类,在调用目标类方法,采用方法
拦截技术,在调用方法之前和之后添加额外扩展功能, 目标类可以不实现接口
package com.ffyc.javapro.oop.design.proxy.cglibproxy;
//具体主题
public class CarFactoryImpl {
public void sell() {
System.out.println("汽车厂卖汽车");
}
}
package com.ffyc.javapro.oop.design.proxy.cglibproxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/*
* 动态代理生成器类
*/
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/*
* 拦截所有目标类方法的调用
* 参数:
* obj 目标实例对象
* method 目标方法的反射对象
* args 方法的参数
* proxy 代理类的实例
*/
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
//代理类调用父类的方法
System.out.println("开始事务");
Object obj1 = proxy.invokeSuper(obj, args);
System.out.println("关闭事务");
return obj1;
}
}
package com.ffyc.javapro.oop.design.proxy.cglibproxy;
public class Test {
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy();
CarFactoryImpl carFactory = (CarFactoryImpl) proxy.getProxy(CarFactoryImpl.class);
carFactory.sell();
}
}
更多推荐

所有评论(0)