Java泛型在设计模式中的应用
Java泛型基础回顾
在深入探讨Java泛型在设计模式中的应用之前,我们先来回顾一下Java泛型的基础知识。泛型是Java 5.0引入的一项强大特性,它允许我们在定义类、接口和方法时使用类型参数。这使得代码可以适应不同的数据类型,同时提供编译时的类型安全检查。
泛型类
泛型类的定义形式为在类名后使用尖括号 <>
包含类型参数。例如,下面是一个简单的泛型类 Box
,用于存储一个任意类型的对象:
public class Box<T> {
private T item;
public void set(T item) {
this.item = item;
}
public T get() {
return item;
}
}
在上述代码中,T
是类型参数,它可以代表任何引用类型。我们可以通过如下方式使用这个泛型类:
Box<Integer> integerBox = new Box<>();
integerBox.set(10);
Integer value = integerBox.get();
这里我们创建了一个 Box<Integer>
实例,它只能存储 Integer
类型的对象,这保证了类型安全,避免了在运行时出现类型转换异常。
泛型接口
泛型接口的定义方式与泛型类类似。例如,定义一个泛型接口 Printer
:
public interface Printer<T> {
void print(T t);
}
然后可以有实现该接口的类:
public class StringPrinter implements Printer<String> {
@Override
public void print(String s) {
System.out.println(s);
}
}
也可以使用匿名内部类实现:
Printer<Integer> integerPrinter = new Printer<Integer>() {
@Override
public void print(Integer i) {
System.out.println(i);
}
};
泛型方法
除了在类和接口中使用泛型,我们还可以定义泛型方法。泛型方法的类型参数在方法返回类型之前声明。例如:
public class GenericMethods {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
}
调用这个泛型方法:
Integer[] intArray = {1, 2, 3};
GenericMethods.printArray(intArray);
这里的 <T>
表示该方法是泛型方法,T
是类型参数,在调用时会根据传入的实际参数类型确定 T
的具体类型。
Java泛型在单例模式中的应用
单例模式是一种常用的设计模式,用于确保一个类在整个应用程序中只有一个实例。传统的单例模式实现如下:
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
然而,这种实现方式存在一些问题,比如在多线程环境下可能会创建多个实例。我们可以使用泛型来实现一个更通用的单例模式,同时利用Java的静态内部类特性来保证线程安全。
public class GenericSingleton<T> {
private GenericSingleton() {
}
public static <T> GenericSingleton<T> getInstance(Class<T> clazz) {
return InnerHolder.INSTANCE;
}
private static class InnerHolder<T> {
private static final GenericSingleton<T> INSTANCE = new GenericSingleton<>();
}
}
使用方式如下:
GenericSingleton<String> stringSingleton = GenericSingleton.getInstance(String.class);
在这个实现中,我们通过泛型使得单例模式可以应用于不同类型的对象,同时静态内部类 InnerHolder
的特性保证了在类加载时才创建单例实例,从而实现了线程安全。
Java泛型在工厂模式中的应用
工厂模式是一种创建型设计模式,它提供了一种创建对象的方式,将对象的创建和使用分离。简单工厂模式是工厂模式的一种基础形式,下面我们来看如何使用泛型来实现简单工厂模式。
简单工厂模式基础实现
假设我们有一个 Shape
接口和两个实现类 Circle
和 Rectangle
:
public interface Shape {
void draw();
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle.");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a rectangle.");
}
}
传统的简单工厂类如下:
public class ShapeFactory {
public Shape createShape(String shapeType) {
if ("circle".equalsIgnoreCase(shapeType)) {
return new Circle();
} else if ("rectangle".equalsIgnoreCase(shapeType)) {
return new Rectangle();
}
return null;
}
}
使用方式:
ShapeFactory factory = new ShapeFactory();
Shape circle = factory.createShape("circle");
circle.draw();
使用泛型改进简单工厂模式
通过泛型,我们可以让工厂类更加通用。假设我们有一个泛型工厂类 GenericFactory
:
import java.util.HashMap;
import java.util.Map;
public class GenericFactory<T> {
private final Map<Class<T>, Supplier<T>> creators = new HashMap<>();
public <S extends T> void register(Class<S> type, Supplier<S> creator) {
creators.put(type, creator);
}
public T create(Class<T> type) {
Supplier<T> creator = creators.get(type);
if (creator == null) {
throw new IllegalArgumentException("No creator registered for type " + type);
}
return creator.get();
}
}
使用方式如下:
GenericFactory<Shape> shapeFactory = new GenericFactory<>();
shapeFactory.register(Circle.class, Circle::new);
shapeFactory.register(Rectangle.class, Rectangle::new);
Shape circle = shapeFactory.create(Circle.class);
circle.draw();
Shape rectangle = shapeFactory.create(Rectangle.class);
rectangle.draw();
在这个泛型工厂类中,register
方法用于注册不同类型对象的创建逻辑,create
方法根据传入的类型创建对象。这样的实现更加灵活和通用,适用于多种类型对象的创建场景。
Java泛型在策略模式中的应用
策略模式定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。
策略模式基础实现
假设我们有一个计算两个数之和的策略接口 SumStrategy
以及两个实现类 NormalSumStrategy
和 AdvancedSumStrategy
:
public interface SumStrategy {
int sum(int a, int b);
}
public class NormalSumStrategy implements SumStrategy {
@Override
public int sum(int a, int b) {
return a + b;
}
}
public class AdvancedSumStrategy implements SumStrategy {
@Override
public int sum(int a, int b) {
// 更复杂的求和逻辑
return a + b + 1;
}
}
使用策略模式的上下文类 SumContext
:
public class SumContext {
private SumStrategy strategy;
public SumContext(SumStrategy strategy) {
this.strategy = strategy;
}
public int executeSum(int a, int b) {
return strategy.sum(a, b);
}
}
使用方式:
SumContext normalContext = new SumContext(new NormalSumStrategy());
int normalSum = normalContext.executeSum(2, 3);
SumContext advancedContext = new SumContext(new AdvancedSumStrategy());
int advancedSum = advancedContext.executeSum(2, 3);
使用泛型改进策略模式
通过泛型,我们可以使策略模式适用于不同类型的计算。例如,定义一个泛型策略接口 GenericCalculationStrategy
:
public interface GenericCalculationStrategy<T> {
T calculate(T a, T b);
}
实现类 GenericSumStrategy
:
import java.math.BigDecimal;
public class GenericSumStrategy implements GenericCalculationStrategy<BigDecimal> {
@Override
public BigDecimal calculate(BigDecimal a, BigDecimal b) {
return a.add(b);
}
}
泛型上下文类 GenericCalculationContext
:
public class GenericCalculationContext<T> {
private GenericCalculationStrategy<T> strategy;
public GenericCalculationContext(GenericCalculationStrategy<T> strategy) {
this.strategy = strategy;
}
public T executeCalculation(T a, T b) {
return strategy.calculate(a, b);
}
}
使用方式:
GenericCalculationStrategy<BigDecimal> sumStrategy = new GenericSumStrategy();
GenericCalculationContext<BigDecimal> context = new GenericCalculationContext<>(sumStrategy);
BigDecimal num1 = new BigDecimal("10.5");
BigDecimal num2 = new BigDecimal("5.5");
BigDecimal result = context.executeCalculation(num1, num2);
System.out.println(result);
通过泛型,策略模式可以应用于更多的数据类型,而不仅仅局限于基本数据类型,增强了代码的复用性和灵活性。
Java泛型在代理模式中的应用
代理模式为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。
代理模式基础实现
假设我们有一个 Subject
接口和一个实现类 RealSubject
:
public interface Subject {
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject is handling request.");
}
}
代理类 ProxySubject
:
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject() {
realSubject = new RealSubject();
}
@Override
public void request() {
System.out.println("Proxy is pre - processing.");
realSubject.request();
System.out.println("Proxy is post - processing.");
}
}
使用方式:
Subject proxy = new ProxySubject();
proxy.request();
使用泛型改进代理模式
使用泛型,我们可以创建一个更通用的代理类,适用于不同类型的目标对象。利用Java的动态代理机制,结合泛型来实现。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class GenericProxy<T> {
private T target;
public GenericProxy(T target) {
this.target = target;
}
public T getProxy() {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Proxy is pre - processing.");
Object result = method.invoke(target, args);
System.out.println("Proxy is post - processing.");
return result;
}
});
}
}
使用方式:
Subject realSubject = new RealSubject();
GenericProxy<Subject> proxy = new GenericProxy<>(realSubject);
Subject proxySubject = proxy.getProxy();
proxySubject.request();
在这个实现中,GenericProxy
类使用泛型来处理不同类型的目标对象,通过Java的动态代理机制,在方法调用前后添加通用的处理逻辑,使得代理模式更加通用和灵活。
Java泛型在观察者模式中的应用
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。
观察者模式基础实现
假设我们有一个 Subject
接口和一个实现类 ConcreteSubject
,以及一个 Observer
接口和一个实现类 ConcreteObserver
:
import java.util.ArrayList;
import java.util.List;
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(this);
}
}
}
public interface Observer {
void update(Subject subject);
}
public class ConcreteObserver implements Observer {
private int observerState;
@Override
public void update(Subject subject) {
observerState = ((ConcreteSubject) subject).getState();
System.out.println("Observer state updated to: " + observerState);
}
}
使用方式:
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer = new ConcreteObserver();
subject.registerObserver(observer);
subject.setState(10);
使用泛型改进观察者模式
通过泛型,我们可以让观察者模式更加通用,适用于不同类型的主题对象和状态。
import java.util.ArrayList;
import java.util.List;
public class GenericSubject<T> {
private List<GenericObserver<T>> observers = new ArrayList<>();
private T state;
public T getState() {
return state;
}
public void setState(T state) {
this.state = state;
notifyObservers();
}
public void registerObserver(GenericObserver<T> observer) {
observers.add(observer);
}
public void removeObserver(GenericObserver<T> observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (GenericObserver<T> observer : observers) {
observer.update(this);
}
}
}
public interface GenericObserver<T> {
void update(GenericSubject<T> subject);
}
public class GenericConcreteObserver<T> implements GenericObserver<T> {
private T observerState;
@Override
public void update(GenericSubject<T> subject) {
observerState = subject.getState();
System.out.println("GenericObserver state updated to: " + observerState);
}
}
使用方式:
GenericSubject<Integer> integerSubject = new GenericSubject<>();
GenericConcreteObserver<Integer> integerObserver = new GenericConcreteObserver<>();
integerSubject.registerObserver(integerObserver);
integerSubject.setState(20);
在这个泛型实现中,GenericSubject
和 GenericObserver
可以处理不同类型的状态,使得观察者模式更加灵活和可复用,能够适应更多不同类型的观察主题和状态变化场景。
Java泛型在装饰器模式中的应用
装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。它通过创建一个包装对象,也就是装饰器,来包裹真实的对象。
装饰器模式基础实现
假设我们有一个 Component
接口和一个实现类 ConcreteComponent
,以及一个装饰器抽象类 Decorator
和一个具体装饰器类 ConcreteDecorator
:
public interface Component {
void operation();
}
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("ConcreteComponent is performing operation.");
}
}
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
@Override
public void operation() {
System.out.println("ConcreteDecorator is pre - processing.");
super.operation();
System.out.println("ConcreteDecorator is post - processing.");
}
}
使用方式:
Component component = new ConcreteComponent();
Component decoratedComponent = new ConcreteDecorator(component);
decoratedComponent.operation();
使用泛型改进装饰器模式
使用泛型可以让装饰器模式更加通用,适用于不同类型的组件。
public interface GenericComponent<T> {
T operation();
}
public class GenericConcreteComponent<T> implements GenericComponent<T> {
private T data;
public GenericConcreteComponent(T data) {
this.data = data;
}
@Override
public T operation() {
System.out.println("GenericConcreteComponent is performing operation.");
return data;
}
}
public abstract class GenericDecorator<T> implements GenericComponent<T> {
protected GenericComponent<T> component;
public GenericDecorator(GenericComponent<T> component) {
this.component = component;
}
@Override
public T operation() {
return component.operation();
}
}
public class GenericConcreteDecorator<T> extends GenericDecorator<T> {
public GenericConcreteDecorator(GenericComponent<T> component) {
super(component);
}
@Override
public T operation() {
System.out.println("GenericConcreteDecorator is pre - processing.");
T result = super.operation();
System.out.println("GenericConcreteDecorator is post - processing.");
return result;
}
}
使用方式:
GenericComponent<String> stringComponent = new GenericConcreteComponent<>("Hello");
GenericComponent<String> decoratedStringComponent = new GenericConcreteDecorator<>(stringComponent);
String result = decoratedStringComponent.operation();
通过泛型,装饰器模式可以处理不同类型的组件,提高了代码的复用性和灵活性,能够适应各种不同类型对象的功能装饰需求。
Java泛型在组合模式中的应用
组合模式将对象组合成树形结构以表示“部分 - 整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式基础实现
假设我们有一个 Component
接口,一个叶子节点类 Leaf
和一个组合节点类 Composite
:
import java.util.ArrayList;
import java.util.List;
public interface Component {
void operation();
}
public class Leaf implements Component {
@Override
public void operation() {
System.out.println("Leaf is performing operation.");
}
}
public class Composite implements Component {
private List<Component> children = new ArrayList<>();
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
@Override
public void operation() {
for (Component child : children) {
child.operation();
}
}
}
使用方式:
Component leaf1 = new Leaf();
Component leaf2 = new Leaf();
Composite composite = new Composite();
composite.add(leaf1);
composite.add(leaf2);
composite.operation();
使用泛型改进组合模式
通过泛型,我们可以使组合模式更加通用,适用于不同类型的组件和操作。
import java.util.ArrayList;
import java.util.List;
public interface GenericComponent<T> {
T operation();
}
public class GenericLeaf<T> implements GenericComponent<T> {
private T data;
public GenericLeaf(T data) {
this.data = data;
}
@Override
public T operation() {
System.out.println("GenericLeaf is performing operation.");
return data;
}
}
public class GenericComposite<T> implements GenericComponent<T> {
private List<GenericComponent<T>> children = new ArrayList<>();
public void add(GenericComponent<T> component) {
children.add(component);
}
public void remove(GenericComponent<T> component) {
children.remove(component);
}
@Override
public T operation() {
T result = null;
for (GenericComponent<T> child : children) {
result = child.operation();
}
return result;
}
}
使用方式:
GenericComponent<Integer> integerLeaf1 = new GenericLeaf<>(10);
GenericComponent<Integer> integerLeaf2 = new GenericLeaf<>(20);
GenericComposite<Integer> integerComposite = new GenericComposite<>();
integerComposite.add(integerLeaf1);
integerComposite.add(integerLeaf2);
Integer result = integerComposite.operation();
通过泛型,组合模式可以处理不同类型的组件和操作结果,增强了代码的通用性和灵活性,能够更好地适应不同类型的“部分 - 整体”层次结构管理需求。
总结泛型在设计模式中的优势
- 类型安全:泛型在编译时进行类型检查,避免了运行时类型转换异常,提高了代码的稳定性和可靠性。在各种设计模式中,如工厂模式创建对象、策略模式执行不同类型的计算等,确保了对象和数据类型的一致性。
- 代码复用:通过泛型,设计模式可以适用于多种不同的数据类型,减少了重复代码。例如在代理模式、装饰器模式和组合模式中,泛型使得这些模式可以处理不同类型的对象,而无需为每种类型单独编写代码。
- 灵活性:泛型增强了设计模式的灵活性,使其能够更好地适应不同的业务需求变化。在观察者模式中,泛型可以处理不同类型的主题状态变化通知,满足各种复杂的观察场景。
- 可读性:使用泛型使得代码更加清晰,明确了类型参数,增强了代码的可读性和可维护性。例如在泛型工厂模式中,通过类型参数清晰地表明了工厂创建对象的类型。
通过深入理解和应用Java泛型在各种设计模式中的特性,我们能够编写出更加健壮、灵活和可维护的Java程序。