跳转到正文
YGJoon 技术博客

Dart 语言中常见的设计模式

发布于:
·1.8k 字 · 约 4 分钟·作者:
单例、工厂、建造者、适配器、装饰器、观察者、策略七个模式的 Dart 实现,附真实项目案例,讲清每个模式真正的落地场景与取舍。
Dart 语言中常见的设计模式文章封面
目录

在 Dart 语言中,可以实现常见的设计模式,这些设计模式提供了在软件开发中解决常见问题的可重用解决方案。设计模式分为三大类:创建型模式、结构型模式 和 行为型模式。我将介绍一些常见的设计模式,并展示如何在 Dart 中实现它们。

单例模式(Singleton Pattern)

一点说明

目的: 确保一个类只有一个实例,并提供一个全局访问点。 在 Dart 中可以通过工厂构造函数来实现单例模式。工厂构造函数允许返回现有的实例,而不是每次都创建新实例。

class Singleton {
  static final Singleton _instance = Singleton._internal();
  
  // 私有构造函数
  Singleton._internal();

  // 工厂构造函数返回唯一实例
  factory Singleton() {
    return _instance;
  }

  void someMethod() {
    print('Doing something');
  }
}

void main() {
  Singleton s1 = Singleton();
  Singleton s2 = Singleton();

  print(identical(s1, s2));  // 输出:true
}

工厂模式(Factory Pattern)

一点说明

目的:提供一种创建对象的接口,让子类决定实例化哪一个类。 在 Dart 中,可以通过工厂构造函数或者独立的工厂类来实现工厂模式。

abstract class Shape {
  void draw();
}

class Circle implements Shape {
  @override
  void draw() {
    print('Drawing a Circle');
  }
}

class Square implements Shape {
  @override
  void draw() {
    print('Drawing a Square');
  }
}

class ShapeFactory {
  static Shape getShape(String shapeType) {
    if (shapeType == 'circle') {
      return Circle();
    } else if (shapeType == 'square') {
      return Square();
    } else {
      throw Exception('Shape not found');
    }
  }
}

void main() {
  Shape shape1 = ShapeFactory.getShape('circle');
  shape1.draw();  // 输出:Drawing a Circle
  
  Shape shape2 = ShapeFactory.getShape('square');
  shape2.draw();  // 输出:Drawing a Square
}

建造者模式(Builder Pattern)

一点说明

目的:用于构建复杂对象,通过一步一步构造,允许分步骤创建对象。 在 Dart 中,建造者模式可以通过类中方法链来实现,常用于构建复杂的对象。

class House {
  String? foundation;
  String? structure;
  String? roof;
  
  @override
  String toString() {
    return 'House with $foundation foundation, $structure structure, and $roof roof';
  }
}

class HouseBuilder {
  final House _house = House();
  
  HouseBuilder setFoundation(String foundation) {
    _house.foundation = foundation;
    return this;
  }
  
  HouseBuilder setStructure(String structure) {
    _house.structure = structure;
    return this;
  }
  
  HouseBuilder setRoof(String roof) {
    _house.roof = roof;
    return this;
  }
  
  House build() {
    return _house;
  }
}

void main() {
  House house = HouseBuilder()
    .setFoundation('Concrete')
    .setStructure('Wood')
    .setRoof('Shingle')
    .build();
  
  print(house);  // 输出:House with Concrete foundation, Wood structure, and Shingle roof
}

适配器模式(Adapter Pattern)

一点说明

目的:将一个类的接口转换成客户端希望的另一种接口,解决接口不兼容的问题。 在 Dart 中,可以通过创建适配器类,将旧接口适配为新的接口。

class OldAudioPlayer {
  void playMp3(String fileName) {
    print('Playing MP3 file: $fileName');
  }
}

abstract class AudioPlayer {
  void play(String fileName);
}

class AudioPlayerAdapter implements AudioPlayer {
  final OldAudioPlayer _oldAudioPlayer;

  AudioPlayerAdapter(this._oldAudioPlayer);

  @override
  void play(String fileName) {
    _oldAudioPlayer.playMp3(fileName);
  }
}

void main() {
  OldAudioPlayer oldPlayer = OldAudioPlayer();
  AudioPlayer player = AudioPlayerAdapter(oldPlayer);
  
  player.play('song.mp3');  // 输出:Playing MP3 file: song.mp3
}

装饰器模式(Decorator Pattern)

一点说明

目的:动态地为对象添加功能。装饰器提供了比继承更灵活的扩展功能的方式。 在 Dart 中,可以通过创建装饰类来增强原始类的功能。

abstract class Coffee {
  final String description = 'Unknown Coffee';
  String getDescription() => description;
  double cost();
}

class SimpleCoffee implements Coffee {
  @override
  String description = 'Simple Coffee';

  @override
  String getDescription() => description;

  @override
  double cost() => 5.0;
}

class MilkDecorator implements Coffee {
  final Coffee _coffee;

  MilkDecorator(this._coffee);

  @override
  String get description => _coffee.description;

  @override
  String getDescription() => _coffee.getDescription() + ', Milk';

  @override
  double cost() => _coffee.cost() + 1.5;
}

class SugarDecorator implements Coffee {
  final Coffee _coffee;

  SugarDecorator(this._coffee);

  @override
  String get description => _coffee.description;

  @override
  String getDescription() => _coffee.getDescription() + ', Sugar';

  @override
  double cost() => _coffee.cost() + 0.5;
}

void main() {
  Coffee coffee = SimpleCoffee();
  print('${coffee.getDescription()} costs \$${coffee.cost()}');
  
  coffee = MilkDecorator(coffee);
  print('${coffee.getDescription()} costs \$${coffee.cost()}');
  
  coffee = SugarDecorator(coffee);
  print('${coffee.getDescription()} costs \$${coffee.cost()}');
}

观察者模式(Observer Pattern)

一点说明

目的:定义对象间一对多的依赖,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 在 Dart 中,可以通过 Stream 来实现观察者模式。注意两点:StreamController 在 dart:async 库里,需要先 import;多个订阅者时要用广播流,单订阅流只能 listen 一次。

import 'dart:async';

class NewsPublisher {
  // broadcast:允许多个订阅者同时监听
  final _newsController = StreamController<String>.broadcast();

  Stream<String> get newsStream => _newsController.stream;

  void publishNews(String news) {
    _newsController.add(news);
  }
}

void main() {
  NewsPublisher publisher = NewsPublisher();
  
  publisher.newsStream.listen((news) {
    print('Subscriber 1 received news: $news');
  });
  
  publisher.newsStream.listen((news) {
    print('Subscriber 2 received news: $news');
  });

  publisher.publishNews('Dart 3.0 Released');
  publisher.publishNews('Flutter 3.0 Released');
}

策略模式(Strategy Pattern)

一点说明

目的:定义一系列算法,并将它们封装在独立的类中,使它们可以互换使用。 在 Dart 中,可以通过接口或者抽象类定义策略,然后通过传递不同的策略类来实现策略模式。

abstract class PaymentStrategy {
  void pay(double amount);
}

class CreditCardPayment implements PaymentStrategy {
  @override
  void pay(double amount) {
    print('Paid \$${amount} with Credit Card');
  }
}

class PaypalPayment implements PaymentStrategy {
  @override
  void pay(double amount) {
    print('Paid \$${amount} with Paypal');
  }
}

class PaymentContext {
  final PaymentStrategy _strategy;

  PaymentContext(this._strategy);

  void executePayment(double amount) {
    _strategy.pay(amount);
  }
}

void main() {
  PaymentContext context = PaymentContext(CreditCardPayment());
  context.executePayment(100.0);  // 输出:Paid $100.0 with Credit Card

  context = PaymentContext(PaypalPayment());
  context.executePayment(200.0);  // 输出:Paid $200.0 with Paypal
}

实战案例:我的项目里真正活着的模式

本文列了 7 种 GoF 模式,但说实话,我的项目里叫得上名字的 GoF 模式几乎没用过。真正天天在用的,是框架级的模式:

GetX 三件套(MVC 变体)——旅行类应用、某物流冷链项目 这些项目,页面结构雷打不动:

pages/travel_select_city/
  index.dart       // 路由入口,只做导出
  controller.dart  // 状态+业务逻辑
  view.dart        // 纯 UI

这是 MVC 的 Dart 方言:Controller 管状态,View 只渲染,index.dart 当门面。好处是新来的人(或者三个月后的我)找代码不用猜——改 UI 去 view,改逻辑去 controller。模式的价值不在”优雅”,在”不用动脑子找文件”。

观察者模式——Dart 里它不叫观察者,叫 Stream。SerialService 的 broadcast StreamController 就是观察者模式:数据生产者完全不知道谁在听,UI、算法、日志各听各的。Dart 把观察者模式做成了语言级设施(Stream),所以你不需要手写 addListener/removeListener 那套样板——最好的设计模式,是你感觉不到它存在的那个。

策略模式——_getFieldType 里那一串 is 判断,本质就是策略模式的手动版:根据 value 的类型选不同的生成策略。没写成正经的 Strategy 类,因为分支逻辑太简单,抽成类反而啰嗦。模式是手段不是目的,if-else 能讲清楚的事,别为了”用模式”而用模式。

总结

上面 7 个模式里,我的项目真正天天打交道的只有观察者(Dart 把它做成了 Stream)和 GetX 那套 MVC 方言。GoF 模式当词典查就行——先把”一个类只干一件事”做到,再谈用哪个模式包装。


分享这篇文章:


相关文章

上一篇
Dart 继承和接口详解
下一篇
Dart 异步编程详解