单例模式
单例模式用来保证类在内存中只能有一个对象,因为对象的创建和销毁都会占用系统资源,一些昂贵的资源可以使用单例模式,节省系统资源
特点:
- 单例类只能有一个实例。
- 单例的类只能自己创建自己的实例。
- 单例类必须能够提供自己的唯一实例给其他类
使用场景
- 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();
}
}
代理模式
代理模式简单的说就是可以在不改变原来代码的情况下,通过引入代理类来扩展功能。
静态代理
比如我们有一个接口角色:增删改查业务, 然后有一个实现类去完成这些具体的实现。
现在我们需要为它增加日志功能,
我们先写一个代理类去继承接口,然后在里面加上增删改查的实现类对象。然后再用对象调用方法,再在方法里加上新的功能。
- 创建一个抽象角色,比如咋们平时做的用户业务,抽象起来就是增删改查!
//抽象角色:增删改查业务
public interface UserService {
void add();
void delete();
void update();
void query();
}
- 我们需要一个真实对象来完成这些增删改查操作
//真实对象,完成增删改查操作的人
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 :在实现类上增加代码 【麻烦!】
- 思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!
- 设置一个代理类来处理日志! 代理角色
//代理角色,在这里面增加日志的实现
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。
原理:待续