1 单例设计模式
单例模式主要是为了避免因为创建多个实例造成的资源浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
1.1饿汉式
使用静态变量,在类被加载时创建对象。
饿汉式:1.构造方法私有化
2.创建当前类对象
3.对外提供公共方法获取对象
public class SingletonHungary {
//1.构造方法私有化
private SingletonHungary(){ }
//2.创建当前类对象
private static SingletonHungary s = new SingletonHungary();
//3.对外提供公共的访问方法将SingletonHungary对象暴露给外部
public static SingletonHungary getInstance() {
return s;
}
}
1.2 懒汉式
只在类对象第一次被调用时,创建实例对象
懒汉式:1. 构造方法私有化
2. 创建当前类的引用
3.对外提供公共的访问方法将对象暴露给外部
public class SingletonLazy {
//1.构造方法私有化
private SingletonLazy(){ }
//2.创建当前类的引用
private static volatile SingletonLazy s;
//3.对外提供公共的访问方法将SingletonHungary对象暴露给外部
public static SingletonLazy getInstance() {
if(s == null){
//这里有可能会有两个线程进来,所以还需要在下面再次判断s是否为null,该方式被称为双重检查
synchronized(SingletonLazy.class) {
if(s == null){
s = new SingletonLazy();
}
}
}
return s;
}
}
2 工厂模式
工厂模式就是用工厂提供的方法代替了new操作,将调用者与实现类进行解耦,实现了创建者与调用者的分离。
工厂模式主要分为:简单工厂模式(静态工厂)、工厂方法模式、抽象工厂。
2.1 简单工厂模式
把对象的创建交由工厂来做。
public class IPhoneFactory {
public static IPhone produce(String model){
if ("iPhoneX".equalsIgnoreCase(model)) {
//生产iPhoneX
return new IPhoneX();
} else if ("iPhone8Plus".equalsIgnoreCase(model)) {
//生产iPhone 8 Plus
return new IPhone8Plus();
}else {
//不生产任何东西
return null;
}
}
}
public class Test01 {
public static void main(String[] args) {
//生产iPhone X手机
IPhone iPhone = IPhoneFactory.produce("iPhoneX");
iPhone.play();
}
}
静态工厂的优点:封装了对象的创建过程,达到解耦的状态。
缺点:拓展性较差。
2.2 工厂方法
工厂方法模式的实质是定义一个用于创建对象的接口,然后让实现这个接口的类来决定创建哪个类的对象。
创建跳舞接口:
public interface Dance {
void dance();
}
创建街舞:
public class JieWu implements Dance {
@Override
public void play() {
System.out.println("this is jiewu.");
}
}
创建舞池:
public interface DancePool {
Dance produce();
}
创建生产街舞的舞池:
public class JieWuFactory implements DancePool {
@Override
public JieWu produce() {
return new JieWu();
}
}
工厂方法模式相对于静态工厂而言在虽然代码量多了一些,但是在程序的扩展性上要更好,倘若再加入生产宅舞的工厂,是不需要修改现有的工厂的。
2.3 抽象工厂
抽象工厂模式提供了一种方式,可以将同一产品族的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。
抽象工厂和工厂方法是类似的,它们的区别在于工厂方法的一个工厂只能创建一个具体产品,而抽象工厂的一个工厂可以创建属于一类类型的多种具体产品。
2.4 三种方式的总结
静态工厂 : 用来生产同一等级结构中的任意产品。产品的创建是由你传入参数决定的。
工厂方法 :用来生产同一等级结构中的固定产品。一个工厂只能生产一个固定的产品。
抽象工厂 :用来生产不同产品族的全部产品。一个工厂可以生产跟该产品相关的一系列产品。
3 代理模式
代理模式(proxy)指的是为一个对象提供一个代理以控制外界对该对象的访问。比如对象A不能直接访问对象B,此时可以为对象B创建一个代理C,然后对象A可以通过访问对象C来简介访问对象B。又比如我们需要增强某个方法,可以通过代理来在方法执行的前后做一些事情,从而达到同样的效果。
代理模式的优点:提高程序的扩展性和可复用性、保护目标对象。
3.1 静态代理
要为对象类创建一个代理类,代理类和相关的方法直接在代码中写死。
3.2 动态代理
动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。动态代理与静态代理原理是一样的,只是它没有具体的代理类,直接在程序运行时动态生成了一个代理对象。(程序中只有对象A的类及其接口,和想要访问A的对象B的类及其接口,没有代理类C)
动态代理的技术实现:
- JDK动态代理技术,底层使用反射原理,要求被代理类必须有接口。
- cglib字节码技术,底层是通过使用一个小而快的字节码处理框架ASM,可以创建类和接口的代理。
JDK动态代理技术代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
ObjectA a = new ObjectA();
//不需要自己创建代理了
//ObjectC c = new ObjectC(a);
//由jdk动态的为你创建一个代理
InterfaceA aProxy = (InterfaceA)Proxy.newProxyInstance(a.getClass().getClassLoader(), a.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("吃饭之前的准备");
Object invoke = method.invoke(a);
System.out.println("吃饭之后的结果");
return invoke;
}
});
ObjectB b = new ObjectB(aProxy);
b.makeFriend();
}
}
4 装饰者模式
给某个对象的功能进行扩展时,可以考虑使用装饰者设计模式。
5 原型模式
所谓原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
- 浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝。
- 深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值。
原型模式优点:
- 如果创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率。
- 可以使用深克隆保持对象的状态。
- 原型模式提供了简化的创建结构。
原型模式缺点:
- 在实现深克隆的时候可能需要比较复杂的代码。
- 需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。
网友评论