Java设计模式-单例/工厂/代理

单例模式

单例模式用来保证类在内存中只能有一个对象,因为对象的创建和销毁都会占用系统资源,一些昂贵的资源可以使用单例模式,节省系统资源

特点

  • 单例类只能有一个实例。
  • 单例的类只能自己创建自己的实例。
  • 单例类必须能够提供自己的唯一实例给其他类

使用场景

  • Spring中的bean使用到了单例模式
  • 计数器使用到了单例模式
  • servlet也是一个单例模式

实现

  • 提供一个本类的唯一实例
  • 私有化构造,防止外界随意创建本类的实例
  • 提供一个公开的静态的方法来让外界获取本类的唯一实例

饿汉式

饿汉式单例模式就是在类加载的时候就立即初始化,并且创建单例对象。不管你有没有用到,都先建好了再说。它绝对线程安全,在线程还没出现以前就实例化了,不可能存在访问安全问题。
优点:线程安全,没有加任何锁、执行效率比较高。
缺点:类加载的时候就初始化,不管后期用不用都占着空间,浪费了内存。
在这里插入图片描述

懒汉式

懒汉式,顾名思义就是实例在用到的时候才去创建,“比较懒”,用的时候才去检查有没有实例,如果有则直接返回,没有则新建。

在这里插入图片描述

双重检测

兼顾性能和线程安全问题

public class Singleton{
    // 提供一个本类的唯一实例 ,volatile 锁
    private volatile static final Singleton instance = null;
    // 私有化构造,防止外界随意创建本类的实例
    private Singleton(){}
    // 提供一个公开的静态的方法来让外界获取本类的唯一实例
    public static getInstance(){
        if(instance == null){
            // 锁住临界资源
            synchronized(Singleton.class){
               	instance = instance == null ? instance = new Singleton() : instance;
            }
        }
        return instance;
    }
}

工厂模式

定义一个用于创建对象的接口,然子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类
工厂模式有一个工厂类,工厂类知道产品类的具体实现细节,并决定何时实例化哪一个类。

简单工厂模式

简单工厂模式:又称为静态工厂方法模式,它属于类创建型模式。
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个工厂类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

有一个父类,这个父类有多个子类,还有一个工厂类,工厂类中创建了父类对象,但是没有实例化,要用到对象的时候,根据传进来的参数不同,选择实例化不同的子类

public interface IVersion {
    void test();
}

public class UserDao1 implements IVersion{
    @Override
    public void test() {
        System.out.println("version1...");
    }
}

public class UserDao2 implements IVersion{
    @Override
    public void test() {
        System.out.println("version2...");
    }
}

public class UserDao3 implements IVersion{

    @Override
    public void test() {
        System.out.println("version3...");
    }
}

/**工厂类**/
public class MyFactory {
    /**
     * 声明常量代替版本号
     */
    public final static int V_ONE = 1;
    public final static int V_TWO = 2;
    public final static int V_THREE = 3;

    /**
     * 创建公开的静态方法
     * @return
     */
    public static IVersion getInstance(Integer version){
        IVersion userDao = null;
        switch (version){
            case V_ONE:
                userDao = new UserDao1();
                break;
            case V_TWO:
                userDao = new UserDao2();
                break;
            case V_THREE:
                userDao = new UserDao3();
                break;
            default:
                System.out.println("简单工厂模式");
        }
        return userDao;
    }
}

抽象工厂

工厂方法模式针对的是一个产品等级结构;
而抽象工厂模式则是针对的多个不同产品等级结构。
或者话,普通工厂模式只能生产具体某一类产品。但是抽象工厂,可以生产多个不同类的产品。打破了工厂与产品之间一对一的关系。
要添加新的大类,就要修改工厂类,违反了开闭原则。

①创建鼠标类的共同接口
//鼠标的接口
interface mouse {
    public void show();
}

②创建戴尔鼠标类实现鼠标接口,即具体的产品类
//具体的产品类(戴尔鼠标),来实现鼠标这个抽象接口
class Dellmouse implements mouse {
    public void show() {
        System.out.println("这是个戴尔鼠标");
    }
}

③创建惠普鼠标类来实现鼠标接口,即具体的产品类
//具体的产品类(惠普鼠标),来实现鼠标这个抽象接口
class Hpmouse implements mouse {
    public void show() {
        System.out.println("这是个惠普鼠标");
    }
}

④创建键盘类的共同接口
//键盘的接口
interface keyboard {
    public void show();
}

⑤创建戴尔键盘类来实现键盘接口,即具体的产品类
//具体的产品类(戴尔键盘),来实现键盘这个抽象接口
class Dellkeyboard implements keyboard {
    public void show() {
        System.out.println("这是个戴尔键盘");
    }
}

⑥创建惠普键盘类来实现键盘接口,即具体的产品类
//具体的产品类(惠普键盘),来实现键盘这个抽象接口
class Hpkeyboard implements keyboard {
    public void show() {
        System.out.println("这是个惠普键盘");
    }
}

⑦创建抽象工厂类共同接口
//抽象工厂类接口
interface PCFactory {
    public mouse createmouse();
    public keyboard createkeyb();
}

⑧创建具体工厂类A,来实现抽象工厂类接口
//具体工厂类A,来实现抽象工厂类接口
 class FactoryA implements PCFactory {
    public mouse createmouse() {     //实现接口的方法
        return new Dellmouse();       //返回创建具体产品类1
    }
   public keyboard createkeyb() {    //实现接口的方法
      return new Dellkeyboard();   //返回创建具体产品类2
    }
}

⑨创建具体工厂类B,来实现抽象工厂类接口
//具体工厂类B,来实现抽象工厂类接口
class FactoryB implements PCFactory {
     public mouse createmouse() {   //实现抽象接口方法
            return new Hpmouse();      //返回创建具体类
    }
    public keyboard createkeyb() {   //实现抽象接口方法
          return new Hpkeyboard();    //返回创建具体类
    }
}

⑩用户端的调用
//用户端的调用
public class user {
	public static void main(String[] args) {
		PCFactory f=new FactoryA();  
        f.createmouse().show();  //用户类只跟接口打交道,只需调用接口的方法
        f.createkeyb().show();
        PCFactory ff=new FactoryB();
        ff.createmouse().show();
        ff.createkeyb().show();
	}
}

代理模式

代理模式简单的说就是可以在不改变原来代码的情况下,通过引入代理类来扩展功能

静态代理

比如我们有一个接口角色:增删改查业务, 然后有一个实现类去完成这些具体的实现。
现在我们需要为它增加日志功能,
我们先写一个代理类去继承接口,然后在里面加上增删改查的实现类对象。然后再用对象调用方法,再在方法里加上新的功能。

  1. 创建一个抽象角色,比如咋们平时做的用户业务,抽象起来就是增删改查!
//抽象角色:增删改查业务
public interface UserService {
  void add();
  void delete();
  void update();
  void query();
}
  1. 我们需要一个真实对象来完成这些增删改查操作
//真实对象,完成增删改查操作的人
public class UserServiceImpl implements UserService {
  public void add() {
    System.out.println("增加了一个用户");
 }
  public void delete() {
    System.out.println("删除了一个用户");
 }
  public void update() {
    System.out.println("更新了一个用户");
 }
  public void query() {
    System.out.println("查询了一个用户");
 }
}
  1. 需求来了,现在我们需要增加一个日志功能,怎么实现!
  • 思路1 :在实现类上增加代码 【麻烦!】
  • 思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!
  1. 设置一个代理类来处理日志! 代理角色
//代理角色,在这里面增加日志的实现
public class UserServiceProxy implements UserService {
  private UserServiceImpl userService;
  public void setUserService(UserServiceImpl userService) {
    this.userService = userService;
 }
  public void add() {
    log("add");
    userService.add();
 }
  public void delete() {
    log("delete");
    userService.delete();
 }
  public void update() {
    log("update");
    userService.update();
 }

动态代理

  • 动态代理的角色和静态代理的一样 .
  • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
  • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
    基于接口的动态代理----JDK动态代理
    基于类的动态代理–cglib

JDK的动态代理只能用来代理接口,
而CGLIB的动态代理既可以代理接口也可以用来代理

JDK动态代理原理

JDK动态代理的核心是InvocationHandler接口和Proxy类,如果代理的类没有实现InvocationHandler接口时,就会使用CGLIB代理

原理:
通过一个代理类区实现InvocationHandler接口,去实现接口的invoke方法,这个方法有三个参数(类,方法,参数),然后通过反射来调用

//这是接口
public interface A{void hello();}
//这是接口实现类
public class B implements A{
@override
void hello()hello
)}

//JDK动态代理过程
代理类implements InvocationHandler{
invoke(proxy , method , argsX){//类 ,方法, 参数
//代理开始
     method.invoke( target , args); //要代理的对象, 参数
//代理结束
  }
}
cglib代理原理

cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final。

原理:待续

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值