【Flutter】设计模式(更新)
Flutter设计模式
文章目录
- Flutter设计模式
- 代码
- 参考文档
- 单例模式
- 项目中的使用
- 工厂模式
- 简单工厂模式
- 项目中的使用(简单工厂)
- 工厂方法模式
- 项目中使用(工厂方法模式)
- 抽象工厂模式
- 观察者模式
- 普通观察者模式
- 适配器模式
- 对象适配器
- 类适配器
代码
https://gitee.com/hellosunshine/design-mode-study-project.git
https://gitee.com/hellosunshine/bilibili_flutter_getx.git
参考文档
https://flutter.cn/community/tutorials/singleton-pattern-in-flutter-n-dart
https://juejin.cn/post/7072625679296102413
https://flutter.cn/docs/cookbook/persistence/key-value
实线与虚线
继承与实现
https://blog.csdn.net/weixin_29230649/article/details/114773522
单例模式
- 单例类中包含一个引用自身类的静态属性实例,且能自行创建这个实例
- 改实例只能通过静态方法访问
- 类构造函数通常没有参数,且被标记为私有,确保不能从类外部实例化该类
///单例
class Singleton {///私有的命名构造函数Singleton._internal();///声明一个单例static final Singleton instance = Singleton._internal();///工厂构造函数返回单例factory Singleton() => instance;
}
///非单例
class NotSingleton {}main() {///创建多个实例,但单例只会有一个Singleton singletonOne = Singleton();Singleton singletonTwo = Singleton();print(singletonOne == singletonTwo); //tureNotSingleton notSingletonOne = NotSingleton();NotSingleton notSingletonTwo = NotSingleton();print(notSingletonOne == notSingletonTwo); //false
}
项目中的使用
- shared_preferences插件(轻量化存储数据)源码里单例
import 'dart:convert';import 'package:shared_preferences/shared_preferences.dart';///持久化存储数据
class SharedPreferenceUtil {static late SharedPreferences _preferences;///初始化SharedPreferencestatic void initSharedPreference() async {_preferences = await SharedPreferences.getInstance();}
}
- 对Dio网络请求单例
import 'package:dio/dio.dart';class HttpBaseRequest {///单例late Dio _dio;HttpBaseRequest._internal() {_dio = Dio();}static final HttpBaseRequest _instance = HttpBaseRequest._internal();factory HttpBaseRequest() => _instance;Future request(String path) async {final result = await _dio.get(path);return result;}
}
工厂模式
简单工厂模式
抽象生产对象
- 定义抽象类
///定义一个抽象方法 人,人会跑
abstract class Person {void run();
}
- 生产对象
///男人
class Man extends Person {@overridevoid run() {print("man can run");}
}///女人
class Woman extends Person {@overridevoid run() {print("woman can run");}
}
- 调用
class SimpleFactoryMode {static void createProduct(int type) {if (type == 1) {Man().run();}if (type == 2) {Woman().run();}}
}
main() {SimpleFactoryMode.createProduct(1); //man can runSimpleFactoryMode.createProduct(2); //woman can run
}
项目中的使用(简单工厂)
场景:在【Flutter】(聊天)中,用户可以发送各类数据,包括文本类型数据、图片数据、视频数据、音频数据。
构建类图
@startuml SendDataDialog
class BaseSendDataModel{List users; //接受者列表String sender; //发送者int date; //日期时间戳String avatar; //头像
}
abstract SendDataModel {+String() buildString //生成数据文本格式
}
note left: 抽象用户发送的数据class TextData {String msg; //文字+String() buildString
}class PictureData {File file; //图片文件+String() buildString
}class VideoData {File file; //视频文件+String() buildString
}class audioData {File file; //音频文件+String() buildString
}class SendDataFactory {{abstract} SendDataModel() createSendData //创建发送消息
}
note left: 简单工厂
BaseSendDataModel <--* SendDataModel
SendDataModel <|.. TextData
SendDataModel <|.. PictureData
SendDataModel <|.. VideoData
SendDataModel <|.. audioData
TextData <.. SendDataFactory
PictureData <.. SendDataFactory
VideoData <.. SendDataFactory
audioData <.. SendDataFactory
@enduml
- 创建抽象类(dart不支持interface)
///生产发送数据的简单工厂
class BaseSendDataModel {late List<String> users; //接受者列表late String sender; //发送者late int date; //日期时间戳late String avatar;BaseSendDataModel({required this.users,required this.sender,required this.date,required this.avatar,}); //头像
}abstract class SendDataModel {late BaseSendDataModel baseSendDataModel;String buildString(); //生成数据文本格式
}
- 实现接口,并构建文字数据类和图片数据类
///文本类型数据
class TextData implements SendDataModel {late String msg;late String dataStr;TextData({required this.msg,required this.baseSendDataModel,});String buildString() {String dataStr = "{\"users\": [\"${baseSendDataModel.users.toString()}\"],""\"msg\": \"$msg\",""\"date\": \"${baseSendDataModel.date}\",""\"avatar\": \"${baseSendDataModel.avatar}\",""\"sender\": \"${baseSendDataModel.sender}\"}";return dataStr;}BaseSendDataModel baseSendDataModel;
}///图片数据
class PhotoData implements SendDataModel {late String photoFilePath;PhotoData({required this.photoFilePath,required this.baseSendDataModel,});String buildString() {String dataStr = "{\"users\": [\"${baseSendDataModel.users.toString()}\"],""\"msg\": \"$photoFilePath\","// "\"msg\": \"${MultipartFile.fromFileSync(photoFilePath)}\",""\"date\": \"${baseSendDataModel.date}\",""\"avatar\": \"${baseSendDataModel.avatar}\",""\"sender\": \"${baseSendDataModel.sender}\"}";return dataStr;}BaseSendDataModel baseSendDataModel;
}
- 构建简单工厂类
///发送数据类型
enum SendDataType {text,video,audio,photo,
}///简单工厂类
class SendDataFactory {static SendDataModel createSendData({required SendDataType sendDataType,required BaseSendDataModel baseSendDataModel,String? msg,String? photoFilePath,}) {if (sendDataType == SendDataType.text) {return TextData(msg: msg!,baseSendDataModel: baseSendDataModel,);} else if (sendDataType == SendDataType.photo) {return PhotoData(photoFilePath: photoFilePath!,baseSendDataModel: baseSendDataModel,);} else {throw Exception();}}
}
- 实现
main() {BaseSendDataModel baseSendDataModel = BaseSendDataModel(users: ["2", "3"],sender: '4',date: 5,avatar: '6',);SendDataModel sendTextData = SendDataFactory.createSendData(sendDataType: SendDataType.text,baseSendDataModel: baseSendDataModel,msg: "我发送了文本消息");SendDataModel sendPhotoData = SendDataFactory.createSendData(sendDataType: SendDataType.photo,baseSendDataModel: baseSendDataModel,photoFilePath: "这是一张图片地址");String textJson = sendTextData.buildString();String photoJson = sendPhotoData.buildString();print(textJson);print(photoJson);
}
-运行
{"users": ["[2, 3]"],"msg": "我发送了文本消息","date": "5","avatar": "6","sender": "4"}
{"users": ["[2, 3]"],"msg": "这是一张图片地址","date": "5","avatar": "6","sender": "4"}Process finished with exit code 0
工厂方法模式
抽象类方法
- 定义一个抽象类,里面声明抽象方法及业务方法
abstrast class LearningFactory {///抽象方法String learning();///业务代码void show() {String skill = learning();print(skill)}
}
- 子类实现这个抽象类,并重写抽象方法
class LearningWalk extends LearningFactory {@overrideString learning() {return "I can walk";}
}class LearningRun extends LearningFactory {@overrideString learning() {return "I can run";}
}
- 实例化子类,调用业务方法
main() {final walkResult = LearningWalk();final runResult = LearningRun();walkResult.show();runResult.show();
}
项目中使用(工厂方法模式)
场景:应对Android和IOS分别实现拍摄媒体功能
@startuml
abstract TakeMediaFactory {+String() methodName+void() invoke
}
note left: 拍摄媒体
class AndroidTakeMedia {+String() methodName
}
class IosTakeMedia {+String() methodName
}
TakeMediaFactory <-- AndroidTakeMedia
TakeMediaFactory <-- IosTakeMedia
@enduml
- 创建抽象类
///拍摄媒体(Android & Ios)
abstract class TakeMediaFactory {late MethodChannel takeMediaChannel;///构建拍摄媒体界面String methodName();///展示void invoke() {ChannelUtil().takeMediaChannel.invokeMethod(methodName(), "").then((value) => print(value));}
}
- 定义子类
///Android拍摄媒体
class AndroidTakeMedia extends TakeMediaFactory {String methodName() {return "takeMediaAndroid";}
}///ios拍摄媒体
class IosTakeMedia extends TakeMediaFactory {String methodName() {return "takeMediaIos";}
}
- Android端监听通道(MainActivity.java)
package com.example.take_media_factory_project;import android.content.Intent;
import android.os.Bundle;import androidx.annotation.Nullable;import java.util.Objects;import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.MethodChannel;public class MainActivity extends FlutterActivity {private static final String takeMediaChannel = "take_media_channel";@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);new MethodChannel(Objects.requireNonNull(getFlutterEngine()).getDartExecutor().getBinaryMessenger(), takeMediaChannel).setMethodCallHandler((call, result) -> {if ("takeMediaAndroid".equals(call.method)) {openTakeMediaView();result.success("启动Android的拍摄功能");} else {result.success("没有对应的方法");}});}private void openTakeMediaView() {Intent intent = new Intent(this, TakeMediaActivity.class);startActivity(intent);}
}
- TakeMediaActivity.java
package com.example.take_media_factory_project;import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Button;import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.Preview;
import androidx.camera.core.UseCaseGroup;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;import com.google.common.util.concurrent.ListenableFuture;import java.util.concurrent.ExecutionException;public class TakeMediaActivity extends AppCompatActivity {//拍照Button takePhotoButton;//预览PreviewView previewView;//权限private static final String[] REQUIRE_PERMISSION = new String[]{Manifest.permission.CAMERA};public static final int REQUEST_CODE_PERMISSIONS = 10;//captureImageCapture imageCapture;ListenableFuture<ProcessCameraProvider> processCameraProviderListenableFuture;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_take_media);takePhotoButton = findViewById(R.id.takePhotoBtn);previewView = findViewById(R.id.preview_view);if (havePermissions()) {initCamera();} else {ActivityCompat.requestPermissions(this, REQUIRE_PERMISSION, REQUEST_CODE_PERMISSIONS);}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == REQUEST_CODE_PERMISSIONS) {initCamera();} else {finish();}}private boolean havePermissions() {for (String permission : REQUIRE_PERMISSION) {if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {return false;}}return true;}private void initCamera() {imageCapture = new ImageCapture.Builder().setFlashMode(ImageCapture.FLASH_MODE_ON).build();processCameraProviderListenableFuture = ProcessCameraProvider.getInstance(this);processCameraProviderListenableFuture.addListener(() -> {try {previewView.setScaleType(PreviewView.ScaleType.FIT_CENTER);Preview preview = new Preview.Builder().build();preview.setSurfaceProvider(previewView.getSurfaceProvider());ProcessCameraProvider processCameraProvider = processCameraProviderListenableFuture.get();processCameraProvider.unbindAll();UseCaseGroup useCaseGroup = new UseCaseGroup.Builder().addUseCase(preview).addUseCase(imageCapture).build();processCameraProvider.bindToLifecycle((LifecycleOwner) TakeMediaActivity.this, CameraSelector.DEFAULT_BACK_CAMERA, useCaseGroup);} catch (ExecutionException | InterruptedException e) {e.printStackTrace();}}, ContextCompat.getMainExecutor(this));}
}
- activity_take_media.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="http://schemas.android.com/apk/res-auto"tools:context=".TakeMediaActivity"><androidx.camera.view.PreviewViewandroid:id="@+id/preview_view"android:layout_width="match_parent"android:layout_height="match_parent" /><Buttonandroid:id="@+id/takePhotoBtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/takePhoto"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_bias=".9" />
</androidx.constraintlayout.widget.ConstraintLayout>
- IOS端待补充
- 调用
- 通道单例
import 'package:flutter/services.dart';class MediaChannel {static String takeMediaChannel = "take_media_channel";
}class ChannelUtil {late MethodChannel takeMediaChannel;ChannelUtil._internal() {///获取媒体takeMediaChannel = MethodChannel(MediaChannel.takeMediaChannel);}static final ChannelUtil _instance = ChannelUtil._internal();factory ChannelUtil() => _instance;
}
- main.dart
void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: HomePage(),);}
}class HomePage extends StatefulWidget {State<HomePage> createState() => _HomePageState();
}class _HomePageState extends State<HomePage> {Widget build(BuildContext context) {return Scaffold(floatingActionButton: FloatingActionButton(onPressed: () {if (defaultTargetPlatform == TargetPlatform.android) {AndroidTakeMedia().invoke();} else if (defaultTargetPlatform == TargetPlatform.iOS) {IosTakeMedia().invoke();}},child: Icon(Icons.phone_iphone_outlined),),);}
}
抽象工厂模式
抽象生产对象的工厂
- 定义抽象的工厂类
abstract class ElectronicProductFactory {Product createComputer();Product createMobile();Product createPad();
}
class Product {String? name;factory Product.createProductOne(String name) {return productOne;}Product._createProductOne();static Product productOne = Product._createProductOne();
}
- 生成一系列对象,他们之间存在一定的联系
///苹果
class Apple extends ElectronicProductFactory {@overrideProduct createComputer() {return Product.createProductOne("Mac");}@overrideProduct createMobile() {return Product.createProductOne("IPhone");}@overrideProduct createPad() {return Product.createProductOne("IPad");}
}///小米
class XiaoMi extends ElectronicProductFactory {@overrideProduct createComputer() {return Product.createProductOne("RedMi");}@overrideProduct createMobile() {return Product.createProductOne("MIUI");}@overrideProduct createPad() {return Product.createProductOne("MIPad");}}
观察者模式
普通观察者模式
- 定义通知和观察者类
///观察者类
class Observer {String name;Observer(this.name);void notify(Notification notification) {print("[${notification.timestamp.toIso8601String()}] Hey$name,${notification.message}!");}
}///通知
class Notification {late DateTime timestamp;late String message;Notification.forNow(String name) {timestamp = DateTime.now();message = "msg:$name";}
}
- 创建一个被观察者类
///被观察者
class Subject {late List<Observer> _observers;///传入观察者列表Subject([List<Observer>? observers]) {_observers = observers ?? [];}///注册观察者void registerObserver(Observer observer) {_observers.add(observer);}///注销观察者void unregisterObserver(Observer observer) {_observers.remove(observer);}///通知观察者void notifyObservers(Notification notification) {for (var observer in _observers) {observer.notify(notification);}}
}
- 创建业务类
///创建一个业务类CoffeeMaker继承被观察者类Subject
class CoffeeMaker extends Subject {CoffeeMaker([List<Observer>? observers]) : super(observers);void brew() {print("Brewing the coffee...");notifyObservers(Notification.forNow("coffee's done"));}
}
- 测试
void main() {///创建观察者var me = Observer("Tyler");///初始化观察者列表var mrCoffee = CoffeeMaker(List.from([me]));///创建观察者var myWife = Observer("Kate");///注册观察者mrCoffee.registerObserver(myWife);///通知观察者mrCoffee.brew();
}
适配器模式
适配器模式可以将不兼容的接口转为可以兼容的接口
对象适配器
- 定义被适配类
import 'dart:convert';
import 'package:xml/xml.dart';
///被适配类
class TargetAdapter {String name;TargetAdapter({required this.name});
}
-规范化结构定义
///规范化结构定义
abstract class ITarget {TargetAdapter getTargetAdapterList();
}
- 不同的对象适配器
///对象适配器
///种类A(json类型的string)
class DataBox {static String receivedJsonData = '''{"name": "data from json"}''';static String receivedXmlData = '''<name>date from xml</name>''';
}class TypeJsonAdapter extends ITarget {var targetAdapter = TargetAdapter();TargetAdapter getTargetAdapterList() {final jsonData = json.decode(DataBox.receivedJsonData);String name = jsonData["name"];targetAdapter.name = name;return targetAdapter;}
}///种类B(xml类型的string)
class TypeXmlAdapter extends ITarget {var targetAdapter = TargetAdapter();TargetAdapter getTargetAdapterList() {XmlDocument xmlDocument = XmlDocument.parse(DataBox.receivedXmlData);String text = xmlDocument.getElement("name")!.text;targetAdapter.name = text;return targetAdapter;}
}
- 客户端调用
///客户端调用
class Client {late ITarget iTarget;Client({required this.iTarget});getString() {final result = iTarget.getTargetAdapterList();print(result.name);}
}main() {Client clientJson = Client(iTarget: TypeJsonAdapter());Client clientXml = Client(iTarget: TypeXmlAdapter());clientJson.getString(); //data from jsonclientXml.getString(); //date from xml
}
类适配器
- 案例
class TargetAdapter {String conCreate() {return "targetAdapter";}}class ClassAdapter extends TargetAdapter {String operate() {return super.conCreate();}
}
- SliverToBoxAdapter案例
CustomScrollView的Sliver属性接收Sliver系列组件 - SliverToBoxAdapter源码
SliverToBoxAdapter
class SliverToBoxAdapter extends SingleChildRenderObjectWidget {/// Creates a sliver that contains a single box widget.const SliverToBoxAdapter({super.key,super.child,});RenderSliverToBoxAdapter createRenderObject(BuildContext context) => RenderSliverToBoxAdapter();
}
这里child传给的父类SingleChildRenderObjectWidget,这里重写抽象类RenderObjectWidget中的createRenderObject
最终返回了RenderSliverToBoxAdapter()
一句话就是将 SingleChildRenderObjectWidget 中 createRenderObject 接口重写转换成可以包含 RenderBox (对应一般 widget 的 RenderObject) 的 RenderSliver (对应 sliver 系列 widget 的 RenderObject),即这里的 RenderSliverToBoxAdapter
【Flutter】设计模式(更新)相关推荐
- Flutter 页面更新流程剖析
文章目录 Flutter页面更新流程剖析 更新流程 渲染过程 视频课程 博主相关文章列表 Flutter 框架实现原理 Flutter 框架层启动源码剖析 Flutter 页面更新流程剖析 Flutt ...
- flutter 热更新
flutter热更新主要是更新代码逻辑和资源两方面.flutter的编译产物刚好吧两个部分分开了.代码逻辑是libapp.so, 资源在flutter_assets目录.要更新flutter就要对li ...
- Flutter 热更新功能实现
Flutter 官方在 GitHub 上声明是暂时不支持热更新的,但是还是有很多能人,通过一些自己的手段,在Android端是能够实现动态更新的功能的. 先看下flutter 的apk 和普通的apk ...
- 一起看 I/O | Flutter 3 更新详解
作者 / Kevin Jamaul Chisholm, Technical Program Manager for Dart and Flutter at Google 又到了 Flutter 稳定版 ...
- Flutter热更新与热加载
之前偶然从Flutter官方文档上看到了支持热更新,当然这是从2019年才开始的 Dynamic updates The Dart Platform, on which Flutter is buil ...
- Android-史上最优雅的实现文件上传、下载及进度的监听,flutter热更新方案
}); 注:如果需要对Http的返回值做解析,可在使用from操作符时,传入一个解析器Parser 带进度上传 带进度上传使用uploadProgress操作符,并结合doOnNext.filter. ...
- Flutter App更新升级
1. 应用程序升级流程 由于在 IOS 中没法直接下载安装,如果版本不一致则直接跳转到IOS应用对应的应用市场就可以了,所以本文仅介绍Android App的升级流程. Android App升级流程 ...
- flutter不支持热更新_Flutter 在安卓上可以实现热更新了
本文由 句号君 授权投稿 原文链接:https://blog.csdn.net/qizewei123/article/details/102963340 Flutter 官方在 GitHub 上声明是 ...
- Flutter 2.2 更新详解
Flutter 2.2 版[1]已正式发布!要获取新版本,您只需切换到 stable 渠道并更新目前安装的 Flutter,或前往 flutter.cn/docs/get-started[2] 从头开 ...
最新文章
- C++ 多线程:时间控制
- cs6 数据库mysql_能mysql内容
- CSS3实例教程:border-image属性实例讲解
- 【CMD】复制并覆盖目标文件
- Redis Sentinel 配置文件
- asp.net core 从 3.1 到 5.0
- java 下拉列表 枚举_「Java三分钟」精准而优雅——枚举类详解
- 今年新增院士中,最年轻的是他
- 前端向后台发送请求有几种方式?
- java实现数据库回滚,java 数据库操作,事宜回滚
- 查询EI检索号的方法
- 客户端单周发版下的多分支自动化管理与实践
- BlazeFace测试
- 安装allennlp
- laravel组件单独加载(2):模型 Eloquent ORM
- 南阳理工学院计算机专业很强吗,南阳理工学院最好的专业?实力最强的是那个专业...
- 原子操作-atomic
- 数据库系统——第九讲 嵌入式SQL语言之基本技巧
- 一个GPIB操作的C#类
- 暑假学习计划回顾总结二
热门文章
- android是手机自拍,安卓6大摄影手机推荐,给喜欢自拍的你
- 【敲级实用】:某小伙写了一个的办公脚本后~变精神了~
- cJSON支持64位数据解析
- STM32中断系统的基本概念
- jsp内置对象--request对象
- 计算机考证word特殊符号
- 45个有助于英文学术论文写作的神网站
- 收藏 不显示删除回复显示所有回复显示星级回复显示得分回复 经典的60句话,慢慢体会 ^_^[...
- 神经网络参数优化算法,神经网络参数优化方案
- php crypt,PHP crypt() 函数