• 设计模式之代理模式
  • 发布于 2个月前
  • 230 热度
    0 评论

让我们先看一下什么是代理模式(Proxy Pattern)和动态代理模式(Dynamic Proxy Pattern)以及这两种设计模式的区别。代理设计模式和动态代理设计模式都属于结构型设计模式,它们都涉及到通过创建代理对象来控制对另一个对象的访问。然而,它们之间有一些关键的区别。


代理设计模式(Proxy Pattern):

旨在为另一个对象提供一个代理或占位符,以控制对该对象的访问。代理对象充当了原始对象的中介,可以在访问原始对象之前或之后执行额外的逻辑,例如记录日志、缓存数据、权限控制等。代理设计模式在静态编译时创建代理对象,并将其与原始对象进行绑定。


动态代理设计模式(Dynamic Proxy Pattern):

是在运行时动态生成代理对象,而不是在编译时创建。动态代理使用了反射机制来动态地创建代理对象,并将方法调用委托给真实对象。它允许在运行时动态地为对象添加额外的功能,而无需修改原始对象的代码。


动态代理设计模式通常涉及到以下几个关键组件:
1.接口:定义了原始对象和代理对象共同实现的方法。
2.真实对象:实现了接口的原始对象。
3.处理器(Handler):负责处理代理对象中的方法调用,通常使用反射机制来调用真实对象的方法。
4.代理工厂(Proxy Factory):根据接口和处理器动态地创建代理对象。

动态代理设计模式的优点在于它提供了更大的灵活性和可扩展性。它允许在运行时根据需要创建代理对象,并且可以根据不同的需求使用不同的处理器。这种动态性使得动态代理在框架开发和AOP(面向切面编程)中得到广泛应用。


代理设计模式和动态代理设计模式都涉及到使用代理对象来控制对另一个对象的访问。代理设计模式在静态编译时创建代理对象,而动态代理设计模式则在运行时动态生成代理对象。动态代理设计模式通过使用反射和动态生成代码的方式提供了更大的灵活性和可扩展性。


下面我们将使用代理设计模式开发一个真实现的场景:
需求介绍:
A模块是宿主,负责管理所有模块,包括B模块。
B模块是登录模块,用户输入用户名和密码进行登录验证,登录成功后需要将登录信息同步到A模块。

开发步骤:
a. 定义登录信息同步的接口 LoginInfoSync,包含一个 syncLoginInfo 方法。
// 堆代码 duidaima.com
// 登录信息同步接口
abstract class LoginInfoSync {
  void syncLoginInfo(String username, String password);
}
b. 在A模块中实现登录信息同步的代理类 LoginProxy,该类实现了 LoginInfoSync 接口,并在 syncLoginInfo 方法中处理登录信息的同步逻辑。
// 登录信息同步代理类
class LoginProxy implements LoginInfoSync {
  void syncLoginInfo(String username, String password) {
    // 在此处实现将登录信息同步到A模块的逻辑
    print('Syncing login info to A module: username=$username, password=$password');
  }
}
c. 在B模块中开发登录页面 LoginPage,用户输入用户名和密码进行登录验证。在登录成功后,创建 LoginProxy 的实例,并调用其 syncLoginInfo 方法将登录信息同步到A模块。
import 'package:flutter/material.dart';

class LoginPage extends StatelessWidget {
  final LoginInfoSync loginProxy;
  // 堆代码 duidaima.com
  LoginPage(this.loginProxy);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              decoration: InputDecoration(
                labelText: 'Username',
              ),
            ),
            TextField(
              decoration: InputDecoration(
                labelText: 'Password',
              ),
              obscureText: true,
            ),
            ElevatedButton(
              onPressed: () {
                // 用户点击登录按钮后的处理
                String username = ''; // 获取输入的用户名
                String password = ''; // 获取输入的密码
                loginProxy.syncLoginInfo(username, password);
              },
              child: Text('Login'),
            ),
          ],
        ),
      ),
    );
  }
}
d. 在A模块的主程序中,创建 LoginProxy 的实例,并将其传递给B模块的登录页面。当用户在B模块中成功登录后,调用代理对象的 syncLoginInfo 方法将登录信息同步到A模块。
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'A Module',
      home: Scaffold(
        appBar: AppBar(
          title: Text('A Module Home'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => LoginPage(LoginProxy()),
                ),
              );
            },
            child: Text('Go to Login'),
          ),
        ),
      ),
    );
  }
}

在上述示例中,我们使用代理设计模式实现了在B模块中的登录页面成功后将登录信息同步到A模块。A模块中的 LoginProxy 类充当代理对象,负责将登录信息同步到A模块。B模块中的 LoginPage 是登录页面,接收 LoginInfoSync 对象作为参数,并在登录成功后调用代理对象的同步方法。


在A模块的主程序中,我们创建了一个 LoginProxy 的实例,并将其传递给B模块的登录页面。当用户点击A模块中的按钮时,跳转到B模块的登录页面,并在登录成功后触发同步信息到A模块的操作。


动态代理:

在Flutter UI开发中,动态代理的概念并不常见,主要原因是Dart语言本身并不直接支持动态代理。动态代理通常需要语言层面的支持,例如Java和JavaScript等语言提供了动态代理的机制,允许在运行时动态地创建和修改对象。然而,Dart语言并没有提供这样的机制。


在Dart中,我们可以通过dart:mirrors库来实现反射,这是一种在运行时检查和修改对象的能力。然而,这个库在Flutter中并不完全可用,特别是在Flutter的Web和移动版本中。这是因为dart:mirrors库的使用会增加应用的大小,并可能降低性能,这对于移动和Web应用来说是不可接受的。因此,Flutter团队决定不在Flutter中支持dart:mirrors库。


这就意味着在Flutter中,你不能直接使用动态代理,因为你不能在运行时动态地创建和修改对象。这对于UI开发来说,可能会带来一些限制。例如,你可能无法在运行时动态地改变一个Widget的行为,或者在运行时动态地添加一个新的Widget。


然而,虽然Flutter并不直接支持动态代理,但它提供了其他的机制来实现动态的UI。例如,你可以使用source_gen这样的库来在编译时生成代码。虽然这不是真正的动态代理,因为所有的代码都是在编译时生成的,但它可以让你在运行时有更多的灵活性。例如,你可以使用source_gen来生成序列化和反序列化的代码,这样你就不需要手动写这些代码了。


本文讨论了代理设计模式和动态代理设计模式,并探讨了它们在Flutter开发中的应用。

代理设计模式允许我们创建代理对象来控制对另一个对象的访问,并在访问原始对象之前或之后执行额外的逻辑。这种模式适用于静态编译时创建代理对象的场景,可以用于实现权限控制、缓存、日志记录等功能。我们以一个在Flutter应用中实现权限控制的示例为例,展示了如何使用代理设计模式来管理用户角色和操作权限。


与此不同,动态代理设计模式在运行时动态生成代理对象,使用反射机制来实现对象的代理。它提供了更大的灵活性和可扩展性,允许在运行时根据需要创建代理对象,并可以在代理对象中添加或修改方法。然而,在Flutter中,动态代理并不直接支持,因为默认情况下,Flutter禁用了dart:mirrors库。我们提到了一些替代方案,如使用第三方库reflectable或代码生成工具来实现类似动态代理的效果。


本文还提供了一个完整的示例,展示了如何在Flutter应用中使用代理设计模式来实现登录信息的同步。该示例涉及两个模块,A模块作为宿主管理所有模块,B模块负责登录页面的开发。我们使用代理设计模式在B模块中创建代理对象,将登录信息同步到A模块。


代理设计模式和动态代理设计模式为我们提供了一种灵活和可扩展的方式来控制对象的访问和扩展对象的功能。在Flutter开发中,虽然动态代理的直接支持受限,但我们可以使用代理设计模式和其他技术来实现类似的效果。根据实际需求,选择适合的设计模式和技术可以帮助我们构建可维护和可扩展的Flutter应用。
希望对您有所帮助谢谢!!!



用户评论