Java 设计模式(java design pattern)

目录

设计模式概念

建模语言(UML)

类与类之间的关系:

面向对象设计原则

单一职责

开闭原则

里氏替换原则

依赖导致

接口隔离

迪米特原则

组合/聚合复用原则

java 设计模式类型

常用设计模式

单例模式

工厂模式(Factory Pattern)

简单工厂模式

工厂方法模式

抽象工厂模式

原型模式

代理模式

静态代理

动态代理

        jdk 代理

        Cglib 代理


设计模式概念

最早概念是在建筑领域产生的,后来被引入到软件开发领域,之前的程序员们,在工作中对某一类问题解决方式进行总结归纳,一种问题对应着一个模式.设计模式就是在面向对象的基础上,更加合理的组织类与类之间的关系.
学习设计模式可以提高编程设计能力,让程序设计更加标准合理,提高开发效率,提高程序的维护性, 能够看懂复杂的源码.

建模语言(UML)

使用特定图形符号,在设计阶段表示类的结构,以及类与类之间的关系.

:矩形

接口:圆形

类与类之间的关系:

依赖关系:(耦合度最弱)在一个类中的方法中作为局部变量,参数用到另一个类.
关联关系:根据关系强弱程度可分为, 聚合(学校 -- 老师)关系和组合关系(头---嘴).
继承关系:(耦合度最大)是父类与子类之间的关系.
实现关系:是接口与实现类之间的关系

面向对象设计原则

单一职责

降低类的职责,一个类负责一个功能,耦合度降低.

开闭原则

对修改关闭,对扩展开放.不建议在新加功能时,对原来的代码进行修改, 可以通过新增加一个类的方式完成.对程序进行抽象化设计.设计出抽象类,接口,不同的功能扩展子列即可.

里氏替换原则

子类继承父类后,尽量不要重写父类的方法,可以新增扩展其他的功能.
保证子类功能的正确性. 不能让功能修改后,导致程序出错.

依赖倒置

上层模块不应该依赖底层模块,它们都应该依赖于抽象.抽象不应该依赖于细节,细节应该依赖于抽象.即上层模块依赖于抽象,不依赖与底层实现细节.

接口隔离

接口功能设计时,应尽量减少一个接口中有过多的功能,可以细分为多个接口.

迪米特原则

一个对象应该对其他对象有最少的了解.在一个类中,应尽量少的使用与其没有直接关系的类(非直接朋友)

组合/聚合复用原则

尽量使用聚合和组合的方式,而不是使用继承.使用继承,为了复用父类中的方法,但是类与类的耦合性高.可以使用关联/依赖,在一个类中达到复用别的类中的方法.

java 设计模式类型

创建型模式:用于描述“怎样创建对象”,主要特点是“将对象的创建与使用分离”。提供了单例、原型、工厂方法、抽象工厂、建造者 5 种创建型模式。
结构型模式:用于描述如何将类或对象按某种布局组成更大的结构,提供了代理、 适配器、桥接、装饰、外观、享元、组合 7 种结构型模式。
行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。提供了模板方法、策略、命令、职责链、状态、 观察者、中介者、迭代器、访问者、备忘录、解释器 11 种行为型模式。

常用设计模式

单例模式

解决的问题: 在一个项目中,一个类只能让它创建一个实例(对象).

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

实现方式: 把构造方私有化.在单例类中,向外界提供一个方法访问到唯一的单例对象.

饿汉式单例(急切式): 在类被加载时,创建初始化,不存在线程安全问题.

//饿汉式单例类.在类初始化时,已经自行实例化 
public class Singleton1 {
    private Singleton1() {}
    private static final Singleton1 single = new Singleton1();
    //静态工厂方法 
    public static Singleton1 getInstance() {
        return single;
    }
}

懒汉式单例: 在使用时获取,需要我们控制创建的数量,在多线程情况下会出现线程安全问题.

//懒汉式单例类.在第一次调用的时候实例化自己 
public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    //静态工厂方法 
    public static Singleton getInstance() {
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
    }
}

工厂模式(Factory Pattern)

有一个工厂,专门负责创建对象,使用对象时,只需要找对应的工厂.

简单工厂模式

由一个父类负责所有产品的生产,根据传入的参数,动态决定创建哪一个实例.

优点:客户端不负责对象的创建,由专门的工厂完成;客户端只负责对象的调用,实现创建和调用的分离,降低客户端代码难度.
缺点:修改产品子类时,要修改简单工厂类,违背了开闭原则.子类产品过多还会使工厂类非常庞大不利维护

工厂方法模式

相比于简单工厂,对工厂进行了抽象,有一个Factory类制定一些规范,实际创建由其子类完成.

优点:实现了创建和调用的分离;添加产品时,只需要添加一个工厂;符合开闭原则.
缺点:同一品牌下有多系列产品时,需要创建多个产品工厂,增加工作量.

抽象工厂模式

一个具体工厂负责创建一系列相互关联的产品.简化调用,更换系列更加方便.

原型模式

原生的new对象,如果对象初始化的内容比较多,每次去new,就比较耗时间. 使用克隆的方式创建对象,提高创建速率.

代理模式

为对象提供一个代理,由代理对象控制对原对象的引用.(中介,律师).

优点:隐藏目标对象;扩展目标对象功能;

静态代理

一个代理类只能代理一个接口下的实现类,要代理多个接口实现类,必须修改代理类.

动态代理

运行时生成代理对象,代理类不需要实现代理的某一类接口

jdk 代理

通过反射实现,借助java.lang.reflect.Proxy,通过固定的规则生成.

实现方法:
1. 编写一个委托类的接口,即静态代理的

public interface UserDao {
      void saveUser();
}

2. 实现一个真正的委托类,即静态代理的

public class VipUserDaoImpl implements UserDao {
    @Override
    public void saveUser() {
        System.out.println("vip用户实现");
    }
}

3. 创建一个动态代理类,实现 InvocationHandler 接口,并重写该 invoke 方法

/*   动态代理类
      代理类不需要实现与目标类相同的接口,这样就可以代理任意的目标类
      但是是有要求的,目标类必需实现接口,此种方式是动态代理的实现方式之一: jdk代理 是一种纯反射机制实现(动态获取目标类接口方法)*/
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);
        System.out.println("之后提交事务");
        return proxy;
    }
    //真正意义上,运行时生成代理对象的方法
    public Object getProxy() {
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
    }
}

4. 在测试类中,生成动态代理的对象。

ublic static void main(String[] args) {
        VipUserDaoImpl vip = new VipUserDaoImpl();
        DynamicProxy dtproxy = new DynamicProxy(vip);//自己创建的代理类对象
        //这才是真正的创建动态代理对象
        UserDao userDao = (UserDao) dtproxy.getProxy();
        //使用代理对象调用接口中的方法,获取当前调用的方法,最终调用invoke方法
        userDao.saveUser();
    }

所有执行代理对象的方法都会被替换成执行invoke方法

Cglib 代理

实现没有接口类的动态代理.通过字节码为一个类创建子类,在子类中采用方法拦截技术,拦截所有父类方法的调用,顺势织入横切逻辑.对于final修饰的方法无法代理.更适合单例对象的代理.

实现方法:
1.需要引入 cglib 的 jar 文件,但是 Spring 的核心包中已经包括了 Cglib 功能,所 以直接引入 spring-core-xxx.jar 即可.
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为 final,否则报错
4.目标对象的方法如果为 final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

创建具体主题

public  class UserDaoImpl{
	    public  void save() {
	        System.out.println("UserDaoImpl:save()");
	    }
}

动态代理类

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;
    }
}

生成动态代理的对象

public static void main(String[] args) {
        CGLibProxy proxy = new CGLibProxy();
        UserDaoImpl userDaoImpl = (UserDaoImpl) proxy.getProxy(UserDaoImpl.class);
        userDaoImpl.save();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值