设计模式的简单应用

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;
    }
}

两者之间的区别及应用场景

  • 懒汉式:

    • 优点:实例在需要时才创建,节省资源。
    • 缺点:需要处理线程安全问题,可能引入额外的同步开销。
  • 饿汉式:

    • 优点:简单,不需要处理线程安全问题。
    • 缺点:实例在类加载时创建,如果实例占用资源较多且不一定会用到,会造成资源浪费。

根据实际情况选择合适的单例实现方式。在多线程环境下,推荐使用双重检查锁或静态内部类实现的懒汉式单例。在资源占用较少且确定会用到实例时,饿汉式单例是一个不错的选择

设计模式通过提供可重用的解决方案,帮助我们更好地组织和管理代码。工厂方法模式、代理模式和单例模式是三种常用的设计模式,每种模式都解决了特定场景下的常见问题,提供了灵活、可扩展的代码结构
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值