常见设计模式

软件设计模式的基本概念

software Design Pattern

 1.解决问题最行之有效的思想。

 2.是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

 3.使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

创建者模式

创建型模型主要关注的是怎样创建对象,主要特点是将对象的创建和使用分离,这样可以降低系统的耦合度,使用者不用关注对象创建的细节。常见的包括单例模式和工厂方法模式

单例模式

        单例模式提供了一种创建对象的最佳方式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式的实现

饿汉式:类加载时就会创建单实例化对象。

懒汉式:类加载时不会创建单实例化对象,而是在首次使用该对象时创建。

饿汉式

实现方法1:静态成员变量方式

public class Singleton {
    //1.私有构造方法
    private Singleton(){}
    //2.在本类中创建本类对象
    private static Singleton instance=new Singleton();
    //3.提供一个公共的访问方式,让外界获取该对象
    public static Singleton getInstance(){
        return instance;
    }
}

基于classloader机制避免了多线程的同步问题。初始化的时候就给装载了,会存在内存浪费,被反射破坏,反序列化影响的问题(可以在构造函数在被第二次调用的时候抛出异常)。

实现方法2:静态代码块

上一种方式的变种写法,都是在类初始化时实例化instance

public class Singleton2 {
    //1.私有构造方法
    private Singleton2(){}
    //2.声明Singleton类型的变量
    private static Singleton2 instance;
    //在静态代码块中进行赋值
    static {
        instance=new Singleton2();
    }
    //3.对外提供获取该类对象的方法
    public static Singleton2 getInstance(){
        return instance;
    }
}

懒汉式

public class Singleton3{
    //私有构造方法
    private Singleton3(){}
    //在成员位置创建该类的对象(volatile禁止指令重排)
    private volatile static Singleton3 instance
    //对外界提供静态方法获取该对象(双重锁定检查确保线程安全)
     public  static Singleton3 getInstance() {
         if(null == instance) {    
             synchronized (Singleton3.class) {
                 if(null == instance) {                    
                     instance = new Singleton3();        
                 }
             }
         }
         return instance;    
     }
}

实现方法2:静态内部类方式。jvm在加载外部类的时候内部类式不会被加载的,只有当其属性,方法被调用时才会被加载,并初始化其静态属性。静态属性被static修饰,保证只被实例化一次,并严格保证实例化顺序。在没有加锁的情况下保证了多线程下的安全,没有任何的性能影响和资源浪费。也会被反射,序列化,反序列化影响(可以在构造函数在被第二次调用的时候抛出异常)

public class Singleton4 {
    //私有构造方法
    private  Singleton4(){}
    //定义一个静态内部类
    private static class SingletonHolder{
        //在内部类中声明并初始化外部类的对象
            private  static  final Singleton4 INSTANCE=new Singleton4();
    }
    //提供公共的访问方式
    public static Singleton4 getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

恶汉式

枚举方式。不考虑浪费内存空间时首选,线程安全,只会装载一次,写法简单,并且是所有单例实现方法中唯一 一个不会被破坏(序列和反序列化,反射破坏单实例化)的单例实现模式。调用时不需要调用getInstance()方法

public enum singletonEnum {
    INSTANCE;
    public void dosomething(){
        System.out.println("枚举大法好,线程安全不能被反射,反序列化破坏,写法简单");
    }
}

单例模式在JDK应用的源码

java.lang.Runtime就是经典的单例模式(饿汉式)。其他使用场景比如数据库连接池(饿汉式),网页的计数器,线程池(threadpool)缓存(cache)默认设置注册表(registry)日志对象等。

简单工厂模式(一种编程习惯,不属于23种经典设计模式)

抽象产品:定义了产品的规范,描述了产品的主要特性和功能。

具体产品:实现或者继承抽象产品的子类。

具体工厂:提供了创建产品的方法,调用者通过调用该方法获取产品。

 

工厂方法模式(完全遵循开闭原则)

概念:定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象,工厂方法使一个产品类的实例化延迟到其工厂的子类。

结构

工厂方法模式的主要角色

抽象工厂(Abstarct Factory):提供了创建产品的接口,调用者通过它来访问具体工厂的工厂方法来创建产品。

具体工厂(Concrete Factory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能

具体产品(Concrete Product):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

抽象工厂模式

抽象工厂(Abstarct Factory):提供了创建产品的接口,它包含了多个创建产品的方法,可以创建多个不同等级的产品。

具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。

抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。

具体产品(Concrete Product):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间多对一的关系。

结构型模式

结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足""合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

 

1、代理模式

概述:由于某些原因需要给某对象提供一个代理控制对该对象的访问,这时访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

java中的代理按照代理类生成时期的不同又分为动态代理和静态代理,静态代理在编译时期就生成,而动态代理则在java运行时自动生成,动态代理又有jdk代理和CGLib代理两种。

结构:代理(proxy)模式分为三种角色

抽象主题类:通过接口或抽象类声明真实主题和代理对象实现的业务方法

真实主题类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象

代理类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以引用,控制或扩展真实主题的功能。

静态代理:

案例:火车站买票

JDK动态代理

 java中提供了一个动态代理类Proxy,Proxy并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法(newProxyInstance方法)来获取对象。

jdk动态代理原理:

 

1、在测试类通过代理对象调用sell()方法

2、根据多态的特性,执行的是代理类($Proxy())中的sell()方法

3、代理类($Proxy())中的sell()方法中又调用了invocationHandle接口的子实现类对象的invoke()方法

4、invoke()方法通过反射执行了真实对象所属类中的sell()方法

CGLIB动态代理

CGLIB是一个功能强大,高性能的代码生成包,它为没有实现接口的类提供代理,为JDK动态代理提供了很好的补充。

三种代理区别

· idk代理和CGLIB代理

使用CGLIB实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK1.6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的类或者方法进行代理,因为CGLib原理是动态生成被代理类的子类。

在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLib代理效率,只有当进行大量调用的时候,JDK1.6和JDK1.7比CGLib代理效率低一点,但是到JDK1.8的时候,JDK代理效率高于CGLIB代理。所以如果有接口使用JDK动态代理,如果没有接口使用cGLTB代理。

· 动态代理和静态代理

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。

如果接口增加一个方法,静态代理模式除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。而动态代理不会出现该问题

优缺点

优点:

1、代理模式在客户端与目标对象中起到一个中介作用和保护目标对象的作用(保护)

2、代理对象可以扩展目标对象的功能(增强)

3、代理模式能够将目标对象与客户端分离,起到降低耦合的作用(解耦)

缺点:

增加了系统的复杂度

                                                 素材来源:9.设计模式-结构型模式-适配器模式概述_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值