1. 工厂方法模式
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定实例化哪个类。通过这种方式,工厂方法模式让类的实例化推迟到子类进行,从而使得设计更加灵活和可扩展。
简单工厂模式
简单工厂模式(Simple Factory Pattern)是工厂模式的简单版本,它使用一个工厂类根据输入条件创建不同类型的对象。简单工厂模式不属于23种经典设计模式
应用场景
- 日志记录器: 需要记录不同种类的日志,如文件日志、数据库日志、控制台日志等。
- 连接器: 需要连接到不同的数据库,如 MySQL、Oracle、SQL Server 等。
// 产品接口 interface Product { void use(); } // 具体产品 class ConcreteProductA implements Product { @Override public void use() { System.out.println("使用产品A"); } } class ConcreteProductB implements Product { @Override public void use() { System.out.println("使用产品B"); } } // 简单工厂 class SimpleFactory { public static Product createProduct(String type) { if (type.equals("A")) { return new ConcreteProductA(); } else if (type.equals("B")) { return new ConcreteProductB(); } return null; } } // 客户端 public class Client { public static void main(String[] args) { Product productA = SimpleFactory.createProduct("A"); productA.use(); Product productB = SimpleFactory.createProduct("B"); productB.use(); } }
优点
- 简单易懂,适合于对象创建逻辑不复杂的情况。
- 客户端不需要知道具体类的名称,只需要知道工厂方法和参数。
缺点
- 违反开闭原则,每当增加新的产品时,都需要修改工厂类代码。
工厂方法模式
优点
- 避免了简单工厂模式中违反开闭原则的缺点。
- 客户端代码和实际创建的对象解耦。
// 产品接口
interface Product {
void use();
}
// 具体产品
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 工厂接口
interface Factory {
Product createProduct();
}
// 具体工厂
class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactoryA();
Product product = factory.createProduct();
product.use();
}
}
2. 代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式可以提供额外的功能,例如权限控制、延迟加载、日志记录等。
应用场景
- 虚拟代理: 在访问对象需要很长时间时,先使用代理对象,等真正需要时再实例化。
- 保护代理: 控制对原始对象的访问。
- 远程代理: 为一个对象在不同地址空间提供局部代表。
优点
- 能够在客户端和目标对象之间增加额外的功能。
- 代理对象可以控制访问权限。
动态代理
动态代理允许在运行时创建代理类,而不是在编译时定义代理类。Java 中有两种主要的动态代理实现方式:JDK 动态代理和 CGLIB 动态代理。
JDK 动态代理
JDK 动态代理基于接口实现,使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 接口
interface Subject {
void request();
}
// 真实主题
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("访问真实主题方法");
}
}
// 动态代理处理器
class ProxyHandler implements InvocationHandler {
private Object target;
public ProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("在调用真实对象之前");
Object result = method.invoke(target, args);
System.out.println("在调用真实对象之后");
return result;
}
}
// 客户端
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject proxyInstance = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new ProxyHandler(realSubject));
proxyInstance.request();
}
}
CGLIB 动态代理
CGLIB(Code Generation Library)是一种基于字节码生成的动态代理机制,可以代理没有实现接口的类。CGLIB 通过生成目标类的子类来实现代理。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 真实主题
class RealSubject {
public void request() {
System.out.println("访问真实主题方法");
}
}
// 动态代理
class CglibProxy implements MethodInterceptor {
private Object target;
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("在调用真实对象之前");
Object result = proxy.invokeSuper(obj, args);
System.out.println("在调用真实对象之后");
return result;
}
}
// 客户端
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
RealSubject proxy = (RealSubject) new CglibProxy().getInstance(realSubject);
proxy.request();
}
}
单例模式
单例模式确保一个类只有一个实例,并提供一个全局访问点。在 Java 中,单例模式的实现主要有两种方式:懒汉式和饿汉式。
懒汉式单例模式
懒汉式单例模式在第一次使用时才创建实例。这种方式可以避免在类加载时创建实例,从而减少内存浪费。
实现方式
1. 基本懒汉式
这种实现方式比较简单,但不是线程安全的。
public class Singleton {
private static Singleton instance;
private Singleton() {
// 私有构造函数,防止实例化
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种实现方式的问题在于,如果多个线程同时调用 getInstance 方法,可能会创建多个实例。
2. 线程安全的懒汉式
通过在 getInstance 方法上加同步关键字 synchronized 来确保线程安全。
public class Singleton {
private static Singleton instance;
private Singleton() {
// 私有构造函数,防止实例化
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种方式虽然解决了线程安全问题,但每次调用 getInstance 方法时都需要进行同步,性能较低。
3. 双重检查锁(Double-Checked Locking)
双重检查锁在保证线程安全的同时,提高了性能。
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
// 私有构造函数,防止实例化
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
在这种实现中,第一次检查 instance 是否为 null 是为了避免不必要的同步,第二次检查是为了在同步块内再次确认实例是否已经创建。
4. 静态内部类
利用类加载机制实现懒加载,同时保证线程安全。
public class Singleton {
private Singleton() {
// 私有构造函数,防止实例化
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式利用静态内部类的特性,只有在 getInstance 方法第一次被调用时,静态内部类才会被加载,从而创建实例。
饿汉式单例模式
饿汉式单例模式在类加载时就创建实例。这种方式确保了实例在类加载时就创建好,但如果实例占用资源较多且不一定会用到,会造成资源浪费。
实现方式
1. 基本饿汉式
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
// 私有构造函数,防止实例化
}
public static Singleton getInstance() {
return INSTANCE;
}
}
在这种实现中,INSTANCE 在类加载时就会被创建。
2. 使用静态代码块
通过静态代码块创建实例,和基本饿汉式没有本质区别,只是提供了一种不同的写法。
public class Singleton {
private static final Singleton INSTANCE;
static {
INSTANCE = new Singleton();
}
private Singleton() {
// 私有构造函数,防止实例化
}
public static Singleton getInstance() {
return INSTANCE;
}
}
两者之间的区别及应用场景
-
懒汉式:
- 优点:实例在需要时才创建,节省资源。
- 缺点:需要处理线程安全问题,可能引入额外的同步开销。
-
饿汉式:
- 优点:简单,不需要处理线程安全问题。
- 缺点:实例在类加载时创建,如果实例占用资源较多且不一定会用到,会造成资源浪费。
根据实际情况选择合适的单例实现方式。在多线程环境下,推荐使用双重检查锁或静态内部类实现的懒汉式单例。在资源占用较少且确定会用到实例时,饿汉式单例是一个不错的选择
1538

被折叠的 条评论
为什么被折叠?



