¿Cómo aplicar el patrón de diseño del método de plantilla en la página flutter?

El salto de enrutamiento de la página en este modo de diseño.

Aquí no se utilizan complementos de contexto ni de enrutamiento.

Definición y composición del patrón del método plantilla.

El patrón Template Method es un patrón muy simple que se puede implementar simplemente usando la herencia.

El patrón del método de plantilla consta de dos partes, la primera parte es la clase principal abstracta y la segunda parte es la subclase de implementación concreta. El marco del algoritmo de la subclase generalmente se encapsula en la clase principal abstracta, incluida la implementación de algunos métodos públicos y el encapsulamiento del orden de ejecución de todos los métodos en la subclase. Al heredar esta clase abstracta, las subclases también heredan toda la estructura del algoritmo y pueden optar por anular los métodos de la clase principal.

Supongamos que tenemos subclases paralelas que tienen algo del mismo comportamiento y algunos comportamientos diferentes entre ellas. Si se mezclan comportamientos iguales y diferentes en las implementaciones de varias subclases, significa que estos mismos comportamientos se repetirán en cada subclase.

Pero, de hecho, el mismo comportamiento se puede mover a otro lugar único, el patrón del método de plantilla nació para resolver este problema. En el patrón del método de plantilla, la misma parte de la implementación de la subclase se traslada a la superclase, y las diferentes partes se dejan a la subclase para que las implemente. Esto también refleja muy bien la idea de generalización.

---- Extraído de "Patrones de diseño de Javascript y práctica de desarrollo"

¿Como alcanzar?

Primero, resumen, cada página tiene un método de salto de ruta, y el nombre de la ruta debe configurarse al saltar. Al mismo tiempo, también pueden realizar pop para eliminar la página actual. Luego, es necesario informar la entrada y salida de cada usuario de la página.

El mismo lugar se encuentra en el salto de la ruta y el método pop, así como el punto enterrado del comportamiento del usuario. La diferencia radica en establecer el nombre de la ruta, que debe implementarse por subclases.

En base a esto, comenzamos a crear una clase abstracta BasePage

/// BasePage 是抽象的页面,所有页面都应该继承于它
/// [ResultType] 是页面 pop 时返回的数据类型。
abstract class BasePage<ResultType> extends StatefulWidget {
  /// 无需context跳转路由的关键,全局导航key
  static final GlobalKey<NavigatorState> navigatorKey = GlobalKey();

  /// 需要子类实现的设置页面名称
  String get pageName;

  /// PageRoute 的 builder
  Widget _pageBuilder(BuildContext context) {
    return this;
  }

  /// 创建一个 PageRoute
  Route<ResultType> createPageRoute(WidgetBuilder builder, RouteSettings settings) {
    return MaterialPageRoute(
      settings: settings,
      builder: builder,
    );
  }

  /// 获取路由设置
  RouteSettings get settings => RouteSettings(name: pageName);

  /// 跳转路由
  Future<ResultType> active({bool replace}) {
    var page = createPageRoute(_pageBuilder, settings);
    assert(page.settings != null); // createPageRoute 函数必须设置 settings
    assert(page.settings.name != null); // settings 中必须包含name。
    if (replace == true) {
      return navigatorKey.currentState.pushReplacement(page);
    } else {
      return navigatorKey.currentState.push(page);
    }
  }
}

复制代码

Es muy simple En la actualidad, solo podemos simplemente saltar, pero podemos extender fácilmente la función de salto active() más tarde para hacer que el salto sea más flexible. Las subpáginas que heredan de él obtienen las capacidades correspondientes. La función activa aquí es un método de plantilla porque encapsula la secuencia de llamada y la lógica de salto.

Muy bien, ahora a navigatorKeyregistrarse en MaterialApp.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: BasePage.navigatorKey,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: '模板方法设计模式',),
    );
  }
}
复制代码

oh! 还有一个 BasePageState ,StatefulWidget 和 State 一直是成对出现的不是吗?我们有了继承于 StatefulWidget 的抽象类 BasePage,但是它并不能提供 initState 和 dispose 用于用户行为埋点。那么我们再创建一个抽象类 BasePageState

/// 持有 BasePage 实例的 State
abstract class BasePageState<T extends BasePage> extends State<T> {
  
  @mustCallSuper
  @override
  void initState() {
    print('[BasePageState]: 记录用户打开 ${widget.pageName} 页面');
    super.initState();
  }

  @mustCallSuper
  @override
  void dispose() {
    print('[BasePageState]: 记录用户离开 ${widget.pageName} 页面');
    super.dispose();
  }

  /// 封装的 pop。
  bool pop<T extends Object>([T result]) {
    return Navigator.pop<T>(context, result);
  }

}
复制代码

到这里,我们已经写好了一个最基础的页面模板。

那么就创建第一个页面并且让它继承自模板吧。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:page_route/base_page.dart';

class PageOne extends BasePage<String> {
  final String title;

  PageOne(this.title);

  @override
  _PageOneState createState() => _PageOneState();

  @override
  String get pageName => 'PageOne';
}

class _PageOneState extends BasePageState<PageOne> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('当前页面是 ${widget.title}'),
              RaisedButton(
                onPressed: () => pop('page one 已结束'),
                child: Text('返回结果'),
              )
            ],
          ),
        ),
      ),
    );
  }

  @override
  void initState() {
    print('${widget.pageName}开始获取数据');
    super.initState();
  }

  @override
  void dispose() {
    print('销毁用不到的对象');
    super.dispose();
  }
}
复制代码

看,这样的话,创建一个页面跟平时创建一个 StatefulWidget 并没有多大区别,而且还获得了路由启动能力。使得我们可以随时随地启动一个页面。pop 当前页面的时候也不需要写一长串的 Navigator.pop<T>(context, result)

个性化路由跳转动画

假使我们要对某个页面加上一些跳转动画,只需要在页面中 override 重写模板的 createPageRoute 方法即可。

先创建第二个页面 PageTwo,然后实现渐隐过度

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:page_route/base_page.dart';

class PageTwo extends BasePage {
  @override
  _PageTwoState createState() => _PageTwoState();

  @override
  String get pageName => 'PageTwo';

  @override
  Route createPageRoute(builder, RouteSettings settings) {
    return PageRouteBuilder(
      transitionDuration: Duration(milliseconds: 500), //动画时间为500毫秒
      settings: settings, // 必须载入 settings
      pageBuilder: (BuildContext context, Animation animation,
          Animation secondaryAnimation) {
        return new FadeTransition(
          //使用渐隐渐入过渡,
          opacity: animation,
          child: builder(context), //路由B
        );
      },
    );
  }
}

class _PageTwoState extends BasePageState<PageTwo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('重写 createPageRoute'),
      ),
      body: Container(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('当前页面的路由动画是 重写 createPageRoute 实现的'),
              RaisedButton(
                onPressed: () => pop('page two 已结束'),
                child: Text('返回结果'),
              )
            ],
          ),
        ),
      ),
    );
  }
}
复制代码

可以看到,只要我们遵循单一职责原则,一定程度上就可以使程序的可扩展性得到提升。打开 PageTwo 页面还是一如既往的简单。

void goPageTwo() {
  PageTwo().active();
}
复制代码

快速创建一个页面

我们知道,ide提供了一些快捷模板(live template)。只要输入 stful 就可以快速创建一个 StatefulWidget。我们可以仿照 stful 写一个 page 快捷模板。先打开 stful 看看。

好的,你已经学会创建快捷模板了,于是你创建了一个 page。

创建新的快捷模板时,一定要记得设置模板用的语言。

截图里面代码不全,下面是完全版:

import 'package:flutter/material.dart';
import 'package:page_route/base_page.dart';

class $PAGE_NAME$ extends BasePage {
  @override
  _$PAGE_NAME$State createState() => _$PAGE_NAME$State();

  @override
  String get pageName => '$PAGE_NAME$';
}

class _$PAGE_NAME$State extends BasePageState<$PAGE_NAME$> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('$END$'),
      ),
      body: Container(),
    );
  }

}
复制代码

此时只需要像写 stful 一样写 page 就可以快速创建一个页面了。

Supongo que te gusta

Origin juejin.im/post/6858884433567547399
Recomendado
Clasificación