Java结构型设计模式分析
一、代理模式
代理模式是一种结构型设计模式,它允许通过代理对象来控制对真实对象的访问。代理对象与真实对象实现相同的接口,客户端通过代理对象间接访问真实对象。
1.1 静态代理
静态代理在编译时就已经确定了代理类,代理类与被代理类实现相同的接口。
// 定义接口
interface Subject {
void request();
}
// 真实主题类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("真实主题执行请求");
}
}
// 代理类
class Proxy implements Subject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("代理类预处理");
realSubject.request();
System.out.println("代理类后处理");
}
}
使用静态代理:
public class StaticProxyExample {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
proxy.request();
}
}
静态代理的优点是实现简单,容易理解。缺点是如果接口方法过多,代理类代码会变得臃肿,且每个被代理类都需要单独创建代理类,不易维护。
1.2 动态代理
动态代理是在运行时动态生成代理类。Java 提供了 java.lang.reflect.Proxy
和 java.lang.reflect.InvocationHandler
来实现动态代理。
// 定义接口
interface Subject {
void request();
}
// 真实主题类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("真实主题执行请求");
}
}
// 调用处理器
class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(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;
}
}
生成动态代理实例:
import java.lang.reflect.Proxy;
public class DynamicProxyExample {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
DynamicProxyHandler handler = new DynamicProxyHandler(realSubject);
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
proxy.request();
}
}
动态代理的优点是可以在运行时动态生成代理类,灵活性高。缺点是相对静态代理,实现较为复杂,需要对反射机制有深入理解。
二、适配器模式
适配器模式用于将一个类的接口转换成客户希望的另一个接口。它使得原本由于接口不兼容而不能一起工作的类可以协同工作。
2.1 类适配器
类适配器通过继承适配者类,实现目标接口。
// 目标接口
interface Target {
void request();
}
// 适配者类
class Adaptee {
public void specificRequest() {
System.out.println("适配者类的特定请求");
}
}
// 类适配器
class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest();
}
}
使用类适配器:
public class ClassAdapterExample {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request();
}
}
类适配器的优点是实现简单,通过继承可以复用适配者的部分代码。缺点是 Java 不支持多重继承,如果适配者类已经有父类,则无法使用类适配器。
2.2 对象适配器
对象适配器通过组合的方式,持有适配者类的实例,并实现目标接口。
// 目标接口
interface Target {
void request();
}
// 适配者类
class Adaptee {
public void specificRequest() {
System.out.println("适配者类的特定请求");
}
}
// 对象适配器
class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
使用对象适配器:
public class ObjectAdapterExample {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
对象适配器的优点是灵活性高,通过组合可以适配不同的适配者对象,且避免了多重继承的问题。缺点是需要额外的对象组合,相对类适配器代码稍显复杂。
三、桥接模式
桥接模式将抽象部分与它的实现部分分离,使它们都可以独立地变化。它通过将抽象和实现之间的耦合关系解耦,提高系统的可扩展性和可维护性。
// 抽象化角色
abstract class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
public abstract void operation();
}
// 扩展抽象化角色
class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
@Override
public void operation() {
System.out.println("扩展抽象化操作");
implementor.operationImpl();
}
}
// 实现化角色
interface Implementor {
void operationImpl();
}
// 具体实现化角色
class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
System.out.println("具体实现化 A 的操作");
}
}
class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
System.out.println("具体实现化 B 的操作");
}
}
使用桥接模式:
public class BridgePatternExample {
public static void main(String[] args) {
Implementor implementorA = new ConcreteImplementorA();
Abstraction abstraction = new RefinedAbstraction(implementorA);
abstraction.operation();
Implementor implementorB = new ConcreteImplementorB();
abstraction = new RefinedAbstraction(implementorB);
abstraction.operation();
}
}
桥接模式的优点是分离了抽象和实现,使得它们可以独立变化,提高了系统的可维护性和可扩展性。缺点是增加了系统的理解和设计难度,需要仔细分析抽象和实现之间的关系。
四、装饰器模式
装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。它通过创建一个装饰器类,将原始对象包装起来,并在保持接口一致的情况下添加新的行为。
// 抽象组件
abstract class Component {
public abstract void operation();
}
// 具体组件
class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("具体组件的操作");
}
}
// 抽象装饰器
abstract class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
// 具体装饰器
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("具体装饰器 A 添加的功能");
}
}
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("具体装饰器 B 添加的功能");
}
}
使用装饰器模式:
public class DecoratorPatternExample {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratedComponentA = new ConcreteDecoratorA(component);
decoratedComponentA.operation();
Component decoratedComponentB = new ConcreteDecoratorB(decoratedComponentA);
decoratedComponentB.operation();
}
}
装饰器模式的优点是可以动态地给对象添加功能,灵活性高,符合开闭原则。缺点是多层装饰会导致系统复杂度增加,调试困难。
五、外观模式
外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
// 子系统类 A
class SubSystemA {
public void operationA() {
System.out.println("子系统 A 的操作");
}
}
// 子系统类 B
class SubSystemB {
public void operationB() {
System.out.println("子系统 B 的操作");
}
}
// 子系统类 C
class SubSystemC {
public void operationC() {
System.out.println("子系统 C 的操作");
}
}
// 外观类
class Facade {
private SubSystemA subSystemA;
private SubSystemB subSystemB;
private SubSystemC subSystemC;
public Facade() {
subSystemA = new SubSystemA();
subSystemB = new SubSystemB();
subSystemC = new SubSystemC();
}
public void operation() {
subSystemA.operationA();
subSystemB.operationB();
subSystemC.operationC();
}
}
使用外观模式:
public class FacadePatternExample {
public static void main(String[] args) {
Facade facade = new Facade();
facade.operation();
}
}
外观模式的优点是简化了子系统的使用,提高了子系统的独立性和可维护性。缺点是不符合开闭原则,如果需要修改子系统的功能,可能需要修改外观类的代码。
六、享元模式
享元模式运用共享技术有效地支持大量细粒度的对象。它通过共享已经存在的对象来减少对象的创建,从而降低内存消耗。
// 享元接口
interface Flyweight {
void operation(String extrinsicState);
}
// 具体享元类
class ConcreteFlyweight implements Flyweight {
private String intrinsicState;
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void operation(String extrinsicState) {
System.out.println("具体享元操作,内部状态:" + intrinsicState + ",外部状态:" + extrinsicState);
}
}
// 享元工厂类
class FlyweightFactory {
private static final Map<String, Flyweight> flyweights = new HashMap<>();
public static Flyweight getFlyweight(String key) {
if (!flyweights.containsKey(key)) {
flyweights.put(key, new ConcreteFlyweight(key));
}
return flyweights.get(key);
}
}
使用享元模式:
public class FlyweightPatternExample {
public static void main(String[] args) {
Flyweight flyweight1 = FlyweightFactory.getFlyweight("A");
Flyweight flyweight2 = FlyweightFactory.getFlyweight("A");
flyweight1.operation("外部状态 1");
flyweight2.operation("外部状态 2");
}
}
享元模式的优点是减少了对象的创建,节省内存,提高系统性能。缺点是增加了系统的复杂度,需要分离内部状态和外部状态,且享元对象的共享状态可能被多个对象修改,需要注意线程安全问题。
七、组合模式
组合模式将对象组合成树形结构以表示“部分 - 整体”的层次结构。它使得用户对单个对象和组合对象的使用具有一致性。
// 抽象组件
abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void display(int depth);
}
// 叶子组件
class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void add(Component component) {
System.out.println("叶子节点不能添加子节点");
}
@Override
public void remove(Component component) {
System.out.println("叶子节点不能移除子节点");
}
@Override
public void display(int depth) {
for (int i = 0; i < depth; i++) {
System.out.print("-");
}
System.out.println(name);
}
}
// 容器组件
class Composite extends Component {
private List<Component> children = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component component) {
children.remove(component);
}
@Override
public void display(int depth) {
for (int i = 0; i < depth; i++) {
System.out.print("-");
}
System.out.println(name);
for (Component child : children) {
child.display(depth + 2);
}
}
}
使用组合模式:
public class CompositePatternExample {
public static void main(String[] args) {
Composite root = new Composite("根节点");
Composite branch1 = new Composite("分支 1");
Composite branch2 = new Composite("分支 2");
Leaf leaf1 = new Leaf("叶子 1");
Leaf leaf2 = new Leaf("叶子 2");
Leaf leaf3 = new Leaf("叶子 3");
root.add(branch1);
root.add(branch2);
branch1.add(leaf1);
branch2.add(leaf2);
branch2.add(leaf3);
root.display(0);
}
}
组合模式的优点是清晰地定义了分层次的复杂对象,表示对象的“部分 - 整体”关系,使得客户端能够一致地处理单个对象和组合对象。缺点是设计较为复杂,当树形结构复杂时,维护和调试困难,且可能会导致性能问题,特别是在遍历树形结构时。
通过对这些 Java 结构型设计模式的分析和代码示例,希望能帮助开发者在实际项目中根据具体需求选择合适的模式,提高代码的可维护性、可扩展性和复用性。在实际应用中,需要综合考虑项目的规模、复杂度、性能要求等因素,灵活运用这些设计模式。同时,不断实践和总结经验,才能更好地掌握和应用它们,打造高质量的 Java 应用程序。