建筑招工网站,百度云登陆首页,seo技术员,网站由哪三部分组成文章目录 一 代理模式1.1 静态代理1.1.1 静态代理的结构1.1.2 静态代理的特点1.1.3 静态代理的应用场景1.1.4 静态代理的案例代码 1.2 JDK动态代理1.2.1 JDK动态代理概述1.2.2 JDK动态代理案例代码1.2.3 JDK动态代理的应用场景1.2.4 JDK动态代理的特点1.2.5 与创建型模式的区别… 文章目录 一 代理模式1.1 静态代理1.1.1 静态代理的结构1.1.2 静态代理的特点1.1.3 静态代理的应用场景1.1.4 静态代理的案例代码 1.2 JDK动态代理1.2.1 JDK动态代理概述1.2.2 JDK动态代理案例代码1.2.3 JDK动态代理的应用场景1.2.4 JDK动态代理的特点1.2.5 与创建型模式的区别 1.3 CGLIB动态代理1.3.1 CGLIB动态代理概述1.3.2 CHLIB动态代理代码案例 1.4 CGLIB vs JDK 动态代理对比1.5 代理模式的经典应用1.6 代理模式的经典应用 二 装饰器模式2.1 装饰器模式的核心组成2.2 装饰器模式的代码案例2.3 装饰器模式的优点2.4 装饰器模式的适用场景 三 适配器模式3.1 适配器模式的主要角色3.2 适配器模式的两种实现方式3.3 适配器模式的代码案例3.3.1 目标接口 Target3.3.2 被适配者 Adaptee3.3.3 对象适配器 ObjectAdapter3.3.4 类适配器 ClassAdapter如果使用继承3.3.5 客户端代码 3.4 适配器模式的应用场景3.5 适配器模式的优缺点 四 组合模式4.1 组合模式的主要角色4.2 组合模式的UML 结构图4.3 组合模式的代码案例4.3.1 定义 Component 接口4.3.2 实现 Leaf 类4.3.3 实现 Composite 类4.3.4 客户端使用 4.4 组合模式的适用场景4.5 组合模式的优缺点 五 门面模式5.1 门面模式的核心思想5.2 门面模式的主要角色5.3 门面模式的代码案例5.4 门面模式的应用场景5.5 门面模式的优缺点 六 桥接模式6.1 桥接模式的主要角色6.2 桥接模式的应用场景6.3 桥接模式的代码案例6.4 桥接模式的优缺点6.5 桥接模式的经典应用 七 享元模式7.1 享元模式的主要角色7.2享元模式的代码实例7.2.1 抽象享元类7.2.2 具体享元类7.2.3 享元工厂类7.2.4 客户端调用 7.3享元模式的优缺点7.4 享元模式的适用场景7.5 享元模式的经典应用 一 代理模式 代理模式的作用是通过代理对象来增强目标对象的功能。利用AOP横切的思想。代理模式的实现方式有三种静态代理动态代理JDK动态代理和CGLIB动态代理。
1.1 静态代理
静态代理是 Java 中一种常见的设计模式属于创建型模式的一种。它主要用于在不修改目标对象的前提下通过代理对象增强目标对象的功能。
1.1.1 静态代理的结构
接口Subject定义目标对象和代理对象的公共接口。目标类RealSubject实现接口提供核心功能。代理类Proxy也实现接口内部持有目标对象的引用可以在调用目标对象的方法前后添加额外操作。
1.1.2 静态代理的特点 优点 符合开闭原则不需要修改目标对象就可以为其增加新的功能。提高代码解耦性代理对象和目标对象职责清晰。 缺点 每个接口都需要一个代理类会导致类数量增加。如果接口方法发生变化代理类也需要同步修改。
1.1.3 静态代理的应用场景
日志记录、性能监控。权限控制。远程调用等需要对目标对象进行封装的场景。
1.1.4 静态代理的案例代码
定义接口 Subject
public interface Subject {void request();
}实现目标类 RealSubject
public class RealSubject implements Subject {Overridepublic void request() {System.out.println(RealSubject: 处理请求);}
}创建代理类 Proxy
public class Proxy implements Subject {private Subject realSubject;public Proxy(Subject realSubject) {this.realSubject realSubject;}Overridepublic void request() {System.out.println(Proxy: 请求前的预处理);realSubject.request(); // 调用真实对象的方法System.out.println(Proxy: 请求后的收尾);}
}使用示例
public class Client {public static void main(String[] args) {Subject realSubject new RealSubject();Subject proxy new Proxy(realSubject);proxy.request(); // 通过代理调用目标对象的方法}
}1.2 JDK动态代理
静态代理适用于目标对象较少且接口固定的场景。如果需要动态地为多个对象生成代理可以使用 JDK 动态代理 或 CGLIB 动态代理。
1.2.1 JDK动态代理概述
JDK动态代理是一种运行时动态生成代理类的技术允许在不修改目标类的情况下增强其功能。它主要依赖于 java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler 接口。Proxy: 提供静态方法用于创建代理实例。InvocationHandler: 定义了代理对象调用方法时的处理逻辑。
1.2.2 JDK动态代理案例代码
创建一个接口如 MyInterface。创建接口的实现类如 MyInterfaceImpl。实现 InvocationHandler 接口定义拦截逻辑。使用 Proxy.newProxyInstance() 方法生成代理对象。
// 接口类
public interface MyInterface {void doSomething();
}
// 实现类
public class MyInterfaceImpl implements MyInterface{Overridepublic void doSomething() {System.out.println(Do something);}
}import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//代理类
public class MyInvocationHandler implements InvocationHandler {private final Object target;public MyInvocationHandler(Object target) {this.target target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(Before method call);Object result method.invoke(target, args);System.out.println(After method call);return result;}}
//测试类
public static void main(String[] args) {// 创建目标对象真实主题它是 MyInterface 接口的具体实现类MyInterface target new MyInterfaceImpl();// 创建一个 InvocationHandler 实例并将目标对象传入用于处理代理对象的方法调用InvocationHandler handler new MyInvocationHandler(target);// 使用 Proxy.newProxyInstance() 方法创建一个代理对象// 参数说明// 1. target.getClass().getClassLoader()指定类加载器用来加载动态生成的代理类// 2. new Class?[] { MyInterface.class }指定代理类要实现的接口列表这里只有一个接口 MyInterface// 3. handler指定代理对象的方法调用处理器即当代理对象的方法被调用时会转交给这个 handler 来处理MyInterface proxy (MyInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), // 类加载器// 要代理的接口 使用new Class?[] { MyInterface.class },或target.getClass().getInterfaces(),target.getClass().getInterfaces(),handler // 方法调用处理器);// 调用代理对象的方法实际会被 InvocationHandler 的 invoke 方法拦截并处理proxy.doSomething();
}1.2.3 JDK动态代理的应用场景
AOP编程如日志记录、性能监控等。远程调用如RMIRemote Method Invocation。权限控制在调用目标方法前进行权限验证。
1.2.4 JDK动态代理的特点
基于接口只能对接口进行代理不能对类进行代理。动态生成字节码在运行时动态生成代理类的字节码。灵活性高可以在不修改目标类的情况下增强其功能。
1.2.5 与创建型模式的区别
创建型模式如工厂模式、单例模式、建造者模式等关注的是对象的创建方式隐藏对象的构造细节。JDK动态代理属于行为型模式关注的是对象之间的交互和职责分配。
1.3 CGLIB动态代理
1.3.1 CGLIB动态代理概述
CGLIBCode Generation Library是一个强大的字节码生成库常用于在运行时动态生成类。它在Java中广泛应用于AOP编程、代理模式实现、ORM框架等场景。CGLIB动态代理的设计结构与使用方式属于结构型设计模式的一种变体非GoF经典23种之一但基于代理模式的扩展。CGLIB动态代理是基于继承机制实现的代理方式适用于没有接口的类。它是Spring AOP底层的重要技术支撑之一具有广泛的工程应用价值。 CGLIB动态代理的核心概念 Enhancer 类 是CGLIB中最核心的类用来创建一个被代理类的子类。通过设置回调Callback拦截方法调用。 MethodInterceptor 接口 用户自定义的拦截器必须实现 intercept() 方法。在该方法中可以加入增强逻辑如日志、事务、权限控制等。 被代理类Target Class 不需要实现接口这是与JDK动态代理的主要区别。CGLIB通过继承方式生成子类来实现代理。 1.3.2 CHLIB动态代理代码案例
需要引入依赖Maven dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.3.0/version/dependency业务代码
public class UserService {public void addUser() {System.out.println(添加用户);}
}实现 MethodInterceptor
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;public class MyMethodInterceptor implements MethodInterceptor {Overridepublic 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;}
}使用 Enhancer 创建代理对象
import net.sf.cglib.proxy.Enhancer;public class CglibProxyDemo {public static void main(String[] args) {Enhancer enhancer new Enhancer();enhancer.setSuperclass(UserService.class); // 设置父类enhancer.setCallback(new MyMethodInterceptor()); // 设置拦截器UserService proxy (UserService) enhancer.create(); // 创建代理对象proxy.addUser(); // 调用方法触发拦截逻辑}
}添加虚拟接参数解决报错
--add-opens java.base/java.langALL-UNNAMED5. 执行结果
前置增强逻辑
添加用户
后置增强逻辑1.4 CGLIB vs JDK 动态代理对比
特性CGLIB动态代理JDK动态代理原理继承目标类生成子类实现接口生成代理是否需要接口否是性能初次生成较慢运行快每次反射调用较慢应用场景Spring AOP无接口、Hibernate懒加载等Spring AOP有接口、RMI 1.5 代理模式的经典应用
Spring中Bean对象的AOP代理。MyBatis中Mapper接口代理对象。MyBatis中JDBC的日志代理。Ribbon或Loadbalancer中的RestTemplate代理对象。OpenFeign的接口代理对象。 1.6 代理模式的经典应用
代理模式在业务系统中的应用一般都是用来拓展增强业务功能。现在需要统计每个请求到来的处理时长如果超过500毫秒就给出警告。
//控制层
public class UserController {private UserService userService;public UserController() {this.userService new UserService(); // 改为构造函数中初始化}public String login() {return userService.login();}
}
// 服务层
public class UserService {public String login(){return 登录成功;}
}
//测试类
public class StartApp {public static void main(String[] args) {UserController userController new UserController();UserController proxy new MethodInterceptor() {public UserController createProxy(Class targetClass) {Enhancer enhancer new Enhancer();enhancer.setSuperclass(targetClass);enhancer.setCallback(this);return (UserController) enhancer.create();}Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {long start System.currentTimeMillis();Object res proxy.invoke(userController, args);long end System.currentTimeMillis();System.out.println(耗时 (end - start));if(end-start500){System.out.println(耗时过长);}return res;}}.createProxy(UserController.class);proxy.login();}
}二 装饰器模式 装饰器模式Decorator Pattern/包装模式是一种结构型设计模式它允许你通过将对象放入包含行为的特殊封装对象中来为原对象增加功能。这种模式比静态子类化更灵活能够在运行时动态地给对象添加职责。装饰模式是一种用于代替继承的技术无需通过继承子类增加子类就能拓展对象的新功能。使用对象的关联关系代替继承关系更加灵活、同时避免类型体系的快速膨胀。
2.1 装饰器模式的核心组成
Component抽象组件定义对象和装饰器的公共接口。ConcreteComponent具体组件实现基础功能的对象。Decorator抽象装饰器继承或实现Component并持有Component对象的引用。ConcreteDecorator具体装饰器为对象增加具体的功能。
2.2 装饰器模式的代码案例
抽象组件 Coffee
public interface Coffee {double cost();String description();
}具体组件 SimpleCoffee
public class SimpleCoffee implements Coffee {Overridepublic double cost() {return 2.0;}Overridepublic String description() {return Simple Coffee;}
}抽象装饰器 CoffeeDecorator
public abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee coffee;}Overridepublic double cost() {return decoratedCoffee.cost();}Overridepublic String description() {return decoratedCoffee.description();}
}具体装饰器 MilkDecorator
public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}Overridepublic double cost() {return super.cost() 0.5; // 加牛奶的价格}Overridepublic String description() {return super.description() , Milk;}
}具体装饰器 SugarDecorator
public class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}Overridepublic double cost() {return super.cost() 0.2; // 加糖的价格}Overridepublic String description() {return super.description() , Sugar;}
}使用示例
public class Main {public static void main(String[] args) {Coffee coffee new SimpleCoffee();System.out.println(Cost: $ coffee.cost() | Description: coffee.description());Coffee milkCoffee new MilkDecorator(new SimpleCoffee());System.out.println(Cost: $ milkCoffee.cost() | Description: milkCoffee.description());Coffee sugarMilkCoffee new SugarDecorator(new MilkDecorator(new SimpleCoffee()));System.out.println(Cost: $ sugarMilkCoffee.cost() | Description: sugarMilkCoffee.description());}
}输出结果
Cost: $2.0 | Description: Simple Coffee
Cost: $2.5 | Description: Simple Coffee, Milk
Cost: $2.7 | Description: Simple Coffee, Milk, Sugar2.3 装饰器模式的优点
灵活性高相比静态继承方式装饰器模式更加灵活可以在运行时动态地组合对象和功能。开闭原则无需修改原有代码即可扩展功能。组合优于继承避免了类爆炸的问题多个装饰器可以自由组合使用。
2.4 装饰器模式的适用场景
当需要动态、透明地给对象添加职责时。当子类扩展不切实际或会导致类爆炸时。当希望保持类责任清晰并避免复杂的继承关系时。
三 适配器模式
适配器模式Adapter Pattern是一种结构型设计模式它允许将一个类的接口转换成客户端期望的另一个接口。适配器模式常用于解决两个不兼容接口之间的适配问题。适配器模式的作用是把两个不兼容的对象通过适配器连接起来工作。在 Java 中java.util.Arrays.asList() 可以将数组转换为 List这其实也是一种适配器模式。Spring 框架中也广泛使用适配器模式来适配不同的事件监听器、处理器等组件。
3.1 适配器模式的主要角色
目标接口Target定义客户端使用的接口。被适配者Adaptee需要被适配的现有类其接口与目标接口不兼容。适配器Adapter实现目标接口并持有被适配者的实例通过组合或继承的方式完成接口转换。
3.2 适配器模式的两种实现方式
对象适配器推荐使用组合的方式适配器包含被适配者的实例。类适配器使用继承的方式适配器继承自被适配者并实现目标接口。
3.3 适配器模式的代码案例
3.3.1 目标接口 Target
public interface Target {void request();
}3.3.2 被适配者 Adaptee
public class Adaptee {public void specificRequest() {System.out.println(Adaptees specific request.);}
}3.3.3 对象适配器 ObjectAdapter
public class ObjectAdapter implements Target {private Adaptee adaptee;public ObjectAdapter(Adaptee adaptee) {this.adaptee adaptee;}Overridepublic void request() {adaptee.specificRequest();}
}3.3.4 类适配器 ClassAdapter如果使用继承
public class ClassAdapter extends Adaptee implements Target {Overridepublic void request() {specificRequest();}
}3.3.5 客户端代码
public class Client {public static void main(String[] args) {// 使用对象适配器Adaptee adaptee new Adaptee();Target target new ObjectAdapter(adaptee);target.request(); // 输出: Adaptees specific request.// 使用类适配器Target classAdapter new ClassAdapter();classAdapter.request(); // 输出: Adaptees specific request.}
}3.4 适配器模式的应用场景
当希望复用已有的类但其接口不符合当前需求时。当需要在不影响现有代码的情况下扩展功能时。当多个子类有不同的接口而客户端希望统一调用时。
3.5 适配器模式的优缺点 优点
提高了类的复用性避免对已有代码进行修改。解耦客户端和被适配者使得两者可以独立变化。符合开闭原则新增适配器不会影响原有系统。 缺点
增加系统的复杂度引入额外的适配类。如果过度使用可能导致系统难以理解和维护。
四 组合模式
组合模式Composite Pattern是一种结构型设计模式它允许你将对象组合成树形结构来表示“部分-整体”的层次关系。通过组合模式客户端可以统一地处理单个对象和对象的组合。组合模式的核心在于统一处理叶子节点Leaf和组合节点Composite。它让客户端无需关心当前操作的是单个对象还是组合对象从而简化了客户端代码。组合模式非常适合用于构建具有递归结构的对象树尤其在需要统一处理个体和群体的情况下非常有用。 4.1 组合模式的主要角色
Component抽象类或接口定义叶子节点和组合节点的公共行为。Leaf表示叶子节点没有子节点实现基础功能。Composite表示组合节点包含子组件可以是叶子节点或其他组合节点并实现了管理子组件的方法如添加、移除等。 4.2 组合模式的UML 结构图 -----------| Component |-----------| operation()|-----------/ \/ \/ \
-------- -------------
| Leaf | | Composite |
---------- -------------
| operation()| | operation() || add(Component)|| remove(Component)|| getChild(int) |---------------4.3 组合模式的代码案例
4.3.1 定义 Component 接口
public interface Component {void operation();
}4.3.2 实现 Leaf 类
public class Leaf implements Component {private String name;public Leaf(String name) {this.name name;}Overridepublic void operation() {System.out.println(Leaf name is doing operation.);}
}4.3.3 实现 Composite 类
import java.util.ArrayList;
import java.util.List;public class Composite implements Component {private String name;private ListComponent children new ArrayList();public Composite(String name) {this.name name;}public void add(Component component) {children.add(component);}public void remove(Component component) {children.remove(component);}Overridepublic void operation() {System.out.println(Composite name is doing operation.);for (Component child : children) {child.operation();}}
}4.3.4 客户端使用
public class Client {public static void main(String[] args) {// 创建叶子节点Component leaf1 new Leaf(Leaf1);Component leaf2 new Leaf(Leaf2);// 创建组合节点Composite composite new Composite(Composite1);composite.add(leaf1);composite.add(leaf2);// 调用组合的操作composite.operation();}
}输出结果
Composite Composite1 is doing operation.
Leaf Leaf1 is doing operation.
Leaf Leaf2 is doing operation.4.4 组合模式的适用场景
表示“部分-整体”的树形结构。希望客户端能够忽略组合对象与单个对象的不同统一处理它们。需要动态地构建层级结构并希望灵活地增删结构中的元素。
4.5 组合模式的优缺点 优点
符合开闭原则增加新的组件类不需要修改现有代码。简化客户端代码使客户端更容易操作复杂结构。提供一致的方式处理单个对象和组合对象。 缺点
如果过度使用组合模式可能会导致系统中出现大量细小的对象增加调试和维护成本。对于不支持树形结构的操作需要额外处理。 五 门面模式
门面模式Facade Pattern/外观模式是 Java 中常用的 结构型设计模式 之一它的主要目的是为子系统中的一组接口提供一个统一的高层接口使得子系统更容易被使用。门面模式是一种非常实用的设计模式特别适用于需要将复杂的子系统简化为一个统一接口的场景。它通过引入一个外观类将客户端与子系统的复杂性隔离开来从而提高了系统的可维护性和易用性。
5.1 门面模式的核心思想
简化复杂系统的调用方式通过引入一个外观类Facade将复杂的调用流程封装起来让客户端只需要与外观类交互。降低耦合度客户端不直接依赖子系统的具体实现而是通过外观类间接访问提高了模块化和可维护性。 5.2 门面模式的主要角色
子系统类SubSystem实现了系统内部的具体功能。外观类Facade提供一个统一的接口封装子系统的调用逻辑。客户端Client使用外观类来完成对子系统的操作。 5.3 门面模式的代码案例
// 子系统类 A
class SubSystemA {public void operationA() {System.out.println(SubSystemA: 操作 A);}
}// 子系统类 B
class SubSystemB {public void operationB() {System.out.println(SubSystemB: 操作 B);}
}// 子系统类 C
class SubSystemC {public void operationC() {System.out.println(SubSystemC: 操作 C);}
}// 外观类
class Facade {private SubSystemA subSystemA;private SubSystemB subSystemB;private SubSystemC subSystemC;public Facade() {this.subSystemA new SubSystemA();this.subSystemB new SubSystemB();this.subSystemC new SubSystemC();}// 高层接口public void operation() {subSystemA.operationA();subSystemB.operationB();subSystemC.operationC();}
}// 客户端
public class Client {public static void main(String[] args) {Facade facade new Facade();facade.operation(); // 调用外观类的方法}
}输出结果
SubSystemA: 操作 A
SubSystemB: 操作 B
SubSystemC: 操作 C5.4 门面模式的应用场景
简化接口当需要隐藏复杂的子系统时可以通过门面模式提供一个更简单的接口。分层架构设计在分层系统中每一层通过门面暴露其服务给上层。遗留系统封装当需要集成旧系统时可以使用门面模式将其封装成一个新接口。解耦减少客户端与子系统的直接依赖提高代码的灵活性。 5.5 门面模式的优缺点 优点
简化客户端调用逻辑。降低系统间的耦合度。更容易维护和扩展。 缺点
不符合开闭原则如果新增子系统或修改现有子系统可能需要修改外观类的代码。 六 桥接模式
桥接模式Bridge Pattern是一种结构型设计模式用于将抽象部分与其具体实现部分分离使它们可以独立变化。它通过组合的方式替代继承避免类爆炸的问题。 6.1 桥接模式的主要角色
桥接模式包含以下核心角色 Abstraction抽象类 定义抽象类的接口并持有对 Implementor 的引用。通常是一个高层次的抽象不直接实现功能而是委托给 Implementor。 RefinedAbstraction扩展抽象类 扩展 Abstraction 类的功能增加更复杂的业务逻辑。 Implementor实现接口 定义实现部分的接口供 Abstraction 调用。通常是不同平台或方式下的统一接口。 ConcreteImplementorA / ConcreteImplementorB具体实现类 实现 Implementor 接口的具体行为。 6.2 桥接模式的应用场景
避免在两个独立维度上使用多重继承导致类数量爆炸。抽象和其实现都要通过子类扩展时希望解耦两者的继承关系。运行时可以切换实现的情况。 6.3 桥接模式的代码案例
// Implementor
interface Implementor {void operationImpl();
}// ConcreteImplementorA
class ConcreteImplementorA implements Implementor {public void operationImpl() {System.out.println(ConcreteImplementorA operation);}
}// ConcreteImplementorB
class ConcreteImplementorB implements Implementor {public void operationImpl() {System.out.println(ConcreteImplementorB operation);}
}// Abstraction
abstract class Abstraction {protected Implementor implementor;protected Abstraction(Implementor implementor) {this.implementor implementor;}public abstract void operation();
}// RefinedAbstraction
class RefinedAbstraction extends Abstraction {public RefinedAbstraction(Implementor implementor) {super(implementor);}public void operation() {System.out.print(RefinedAbstraction: );implementor.operationImpl();}
}//测试类
public class Client {public static void main(String[] args) {Implementor implA new ConcreteImplementorA();Implementor implB new ConcreteImplementorB();Abstraction abstrA new RefinedAbstraction(implA);Abstraction abstrB new RefinedAbstraction(implB);abstrA.operation(); // 输出RefinedAbstraction: ConcreteImplementorA operationabstrB.operation(); // 输出RefinedAbstraction: ConcreteImplementorB operation}
}6.4 桥接模式的优缺点
优点
解耦抽象与实现允许两者独立变化。提高可扩展性新增一个维度只需扩展不需修改。避免类爆炸问题通过组合代替继承。 缺点
增加系统理解难度需要正确识别两个独立变化的维度。接口设计要求高必须提前规划好 Implementor 和 Abstraction 的接口。 6.5 桥接模式的经典应用
不同操作系统上的图形绘制库图形是抽象渲染是实现。多种支付渠道微信、支付宝与多种支付方式扫码、刷脸的组合。消息通知系统消息类型文本、图片与发送渠道短信、邮件、站内信的组合。JDBCjava与数据库交互的API将java应用程序与不同数据库之间的连接进行解耦。JDBC提供标准的接口作为抽象部分具体的数据库驱动程序作为实现部分。SLF4J日志框架提供LoggerAppender和Formatter。他们三个表示不同的维度。Logger表示日志记录所属的类Appender表示日志的输出Formatter表示日志记录的格式。三个维度可以有多种不同的实现利用桥接模式可以实现三种维度的任意组合。 七 享元模式
享元模式Flyweight Pattern是 Java 中常用的结构型设计模式之一主要用于减少创建和管理大量相似对象时的内存开销。 享元模式的核心思想通过共享技术来有效支持大量细粒度的对象的重用。适用于对象数量巨大大部分对象的状态可以外部化即对象之间差异小 享元对象能做到共享的关键是区分了内部状态和外部状态。 内部状态可以共享不会随环境的改变而变化外部状态不可以共享会随环境的改变而变化 例如象棋上棋子的颜色形状大小是共享属性内部状态而位置是不可共享属性外部状态。
7.1 享元模式的主要角色
角色描述Flyweight抽象享元类定义公共接口或抽象类包含一个operation()方法。ConcreteFlyweight具体享元类实现抽象享元接口存储内部状态intrinsic state。UnsharedConcreteFlyweight非共享享元类不参与共享的享元类通常用于组合结构。FlyweightFactory享元工厂类负责创建和管理享元对象通常使用 Map 缓存已创建的享元对象。 7.2享元模式的代码实例
7.2.1 抽象享元类
public interface Flyweight {void operation(String extrinsicState); // extrinsicState 是外部状态
}7.2.2 具体享元类
public class ConcreteFlyweight implements Flyweight {private String intrinsicState; // 内部状态可共享public ConcreteFlyweight(String intrinsicState) {this.intrinsicState intrinsicState;}Overridepublic void operation(String extrinsicState) {System.out.println(内部状态: intrinsicState , 外部状态: extrinsicState);}
}7.2.3 享元工厂类
import java.util.HashMap;
import java.util.Map;public class FlyweightFactory {private MapString, Flyweight flyweights new HashMap();public Flyweight getFlyweight(String key) {if (!flyweights.containsKey(key)) {flyweights.put(key, new ConcreteFlyweight(key));}return flyweights.get(key);}public int getTotalFlyweights() {return flyweights.size();}
}7.2.4 客户端调用
public class Client {public static void main(String[] args) {FlyweightFactory factory new FlyweightFactory();Flyweight f1 factory.getFlyweight(A);Flyweight f2 factory.getFlyweight(B);Flyweight f3 factory.getFlyweight(A); // 共享已有对象f1.operation(X);f2.operation(Y);f3.operation(Z);System.out.println(实际创建的享元对象数量 factory.getTotalFlyweights());}
}输出结果
内部状态: A, 外部状态: X
内部状态: B, 外部状态: Y
内部状态: A, 外部状态: Z
实际创建的享元对象数量27.3享元模式的优缺点 优点
节省内存通过共享对象减少重复创建对象的数量。提高性能避免频繁的对象创建与销毁。 缺点
对JVM回收不友好因为工厂类一直保持对享元类的引用造成享元类在没有任何引用的情况下也不会被JVM回收。
7.4 享元模式的适用场景
系统中存在大量相似对象如字符、图形、连接池等。需要将对象的状态分为内部状态和外部状态 内部状态不变且可共享如字体名称外部状态随环境变化而变化如字体大小、颜色 7.5 享元模式的经典应用
文本编辑器中对字符的处理每个字符作为享元对象游戏开发中的粒子系统棋类游戏的棋子对象数据库连接池、线程池等资源池化管理