Dart 语言速成:从函数闭包到面向对象,30 分钟补齐 Flutter 开发的语言短板(二)
·

面向对象编程就像建造房子,我们先设计图纸(类),然后按图纸建造房子(对象)。
3.1 类和对象
// 设计图纸:人的基本信息
class Person {
// 属性 - 就像人的特征
String name;
int age;
double height;
// 构造函数 - 就像出生证明,创建人的时候必须填写的信息
Person(this.name, this.age, this.height);
// 方法 - 就像人能做的事情
void introduce() {
print('大家好,我是$name,今年$age岁,身高${height}米');
}
void celebrateBirthday() {
age++;
print('$name过生日了!现在$age岁了!');
}
// 计算属性 - 就像根据现有信息计算出的新信息
bool get isAdult => age >= 18;
String get ageGroup {
if (age < 13) return '儿童';
if (age < 18) return '青少年';
if (age < 60) return '成年人';
return '老年人';
}
}
// 按图纸建造房子(创建对象)
var person1 = Person('小明', 20, 1.75);
var person2 = Person('小红', 16, 1.65);
// 使用对象
person1.introduce(); // 输出:大家好,我是小明,今年20岁,身高1.75米
person2.celebrateBirthday(); // 小红过生日了!现在17岁了!
print(person1.isAdult); // true
print(person2.ageGroup); // 青少年
3.2 继承 - 就像家族传承
// 基础类 - 就像家族的共同特征
class Animal {
String name;
int age;
Animal(this.name, this.age);
void eat() {
print('$name正在吃东西');
}
void sleep() {
print('$name正在睡觉');
}
}
// 继承类 - 就像继承了家族特征,但有自己的特色
class Dog extends Animal {
String breed; // 品种
// 调用父类构造函数
Dog(String name, int age, this.breed) : super(name, age);
// 狗特有的行为
void bark() {
print('$name在汪汪叫');
}
void wagTail() {
print('$name开心地摇尾巴');
}
// 重写父类方法 - 就像有自己的吃饭方式
void eat() {
print('$name正在啃骨头');
}
}
class Cat extends Animal {
bool isIndoor; // 是否室内猫
Cat(String name, int age, this.isIndoor) : super(name, age);
void meow() {
print('$name在喵喵叫');
}
void climb() {
print('$name正在爬树');
}
void eat() {
print('$name正在优雅地吃猫粮');
}
}
// 使用继承
var dog = Dog('旺财', 3, '金毛');
var cat = Cat('咪咪', 2, true);
dog.eat(); // 旺财正在啃骨头
dog.bark(); // 旺财在汪汪叫
cat.eat(); // 咪咪正在优雅地吃猫粮
cat.meow(); // 咪咪在喵喵叫
3.3 抽象类和接口详解
🤔 Dart中有interface关键字吗?
答案:没有! 但Dart有更灵活的接口实现方式。
在Dart中,接口的实现有以下几种方式:
| 方式 | 关键字 | 特点 | 使用场景 |
|---|---|---|---|
| 抽象类 | abstract class |
可以有抽象方法和具体方法 | 定义基础框架 |
| 隐式接口 | implements |
任何类都可以作为接口 | 强制实现所有方法 |
| Mixin | mixin |
可以混入多个功能 | 功能组合 |
🏗️ 1. 抽象类 - 建筑蓝图
// 抽象类 - 就像建筑蓝图,定义了基本结构但不能直接建造
abstract class Vehicle {
String brand;
int year;
Vehicle(this.brand, this.year);
// 抽象方法 - 必须被子类实现(就像蓝图上的"待定"部分)
void start();
void stop();
double getFuelEfficiency();
// 具体方法 - 可以直接使用(就像蓝图上的标准部分)
void displayInfo() {
print('品牌:$brand,年份:$year');
}
void honk() {
print('$brand车辆鸣笛:嘀嘀!');
}
}
// 不能直接创建抽象类的实例
// var vehicle = Vehicle('Toyota', 2023); // ❌ 错误!
🔧 2. 隐式接口 - 任何类都可以是接口
在Dart中,每个类都隐式地定义了一个接口,包含该类的所有实例成员。
// 普通类 - 同时也是一个隐式接口
class Printer {
String brand;
bool isConnected;
Printer(this.brand, this.isConnected);
void doPrint(String document) {
print('$brand打印机正在打印:$document');
}
void connect() {
isConnected = true;
print('$brand打印机已连接');
}
}
// 使用implements关键字实现接口
// 激光打印机
class LaserPrinter implements Printer {
String brand;
bool isConnected;
LaserPrinter(this.brand, this.isConnected);
// 必须实现接口中的所有方法
void doPrint(String document) {
print('激光打印机$brand高速打印:$document');
}
void connect() {
isConnected = true;
print('激光打印机$brand通过USB连接');
}
// 可以添加自己的方法
void warmUp() {
print('激光打印机正在预热...');
}
}
// 喷墨打印机
class InkjetPrinter implements Printer {
String brand;
bool isConnected;
InkjetPrinter(this.brand, this.isConnected);
void doPrint(String document) {
print('喷墨打印机$brand彩色打印:$document');
}
void connect() {
isConnected = true;
print('喷墨打印机$brand通过WiFi连接');
}
void checkInkLevel() {
print('检查墨水余量...');
}
}
🎭 3. Mixin - 功能模块
// Mixin - 就像功能模块,可以组合使用
// 飞行功能
mixin Flyable {
double altitude = 0.0;
void fly() {
altitude = 1000.0;
print('正在飞行中,高度:${altitude}米');
}
void land() {
altitude = 0.0;
print('已着陆');
}
}
// 游泳功能
mixin Swimmable {
double depth = 0.0;
void swim() {
depth = 10.0;
print('正在游泳中,深度:${depth}米');
}
void surface() {
depth = 0.0;
print('浮出水面');
}
}
// 行走功能
mixin Walkable {
double speed = 0.0;
void walk() {
speed = 5.0;
print('正在行走,速度:${speed}公里/小时');
}
void run() {
speed = 15.0;
print('正在奔跑,速度:${speed}公里/小时');
}
}
🦆 4. 实际应用示例
// 基础动物类
abstract class Animal {
String name;
int age;
Animal(this.name, this.age);
// 抽象方法
// 发出声音
void makeSound();
// 吃东西
void eat();
// 具体方法
void sleep() {
print('$name正在睡觉...');
}
}
// 鸭子 - 会飞、会游泳、会走路
class Duck extends Animal with Flyable, Swimmable, Walkable {
Duck(String name, int age) : super(name, age);
void makeSound() {
print('$name:嘎嘎嘎!');
}
void eat() {
print('$name正在吃小鱼和水草');
}
}
// 企鹅 - 会游泳、会走路,但不会飞
class Penguin extends Animal with Swimmable, Walkable {
Penguin(String name, int age) : super(name, age);
void makeSound() {
print('$name:嘎嘎嘎!(企鹅叫声)');
}
void eat() {
print('$name正在吃鱼');
}
// 企鹅特有的滑行能力
void slide() {
print('$name正在冰面上滑行!');
}
}
// 老鹰 - 会飞、会走路
class Eagle extends Animal with Flyable, Walkable {
Eagle(String name, int age) : super(name, age);
void makeSound() {
print('$name:啾啾!');
}
void eat() {
print('$name正在捕食小动物');
}
void hunt() {
print('$name正在高空盘旋寻找猎物');
}
}
🏭 5. 多接口实现
// 定义多个接口
abstract class Drawable {
void draw();
}
abstract class Clickable {
void onClick();
}
abstract class Resizable {
void resize(double width, double height);
}
// 实现多个接口
class Button implements Drawable, Clickable, Resizable {
double width;
double height;
String text;
Button(this.width, this.height, this.text);
void draw() {
print('绘制按钮:$text (${width}x${height})');
}
void onClick() {
print('按钮被点击:$text');
}
void resize(double width, double height) {
this.width = width;
this.height = height;
print('按钮大小调整为:${width}x${height}');
}
}
// 使用接口类型
void handleDrawable(Drawable drawable) {
drawable.draw();
}
void handleClickable(Clickable clickable) {
clickable.onClick();
}
// 使用示例
void main(){
var button = Button(100, 50, '确定');
handleDrawable(button);
handleClickable(button);
button.resize(120, 60);
}
💡 6. 接口使用最佳实践
// ✅ 好的实践:使用抽象类定义接口
abstract class PaymentProcessor {
Future<bool> processPayment(double amount);
Future<void> refund(String transactionId);
String getProviderName();
}
class AlipayProcessor implements PaymentProcessor {
Future<bool> processPayment(double amount) async {
print('支付宝处理支付:¥$amount');
// 模拟异步处理
await Future.delayed(Duration(seconds: 1));
return true;
}
Future<void> refund(String transactionId) async {
print('支付宝退款:$transactionId');
await Future.delayed(Duration(milliseconds: 500));
}
String getProviderName() => '支付宝';
}
class WechatPayProcessor implements PaymentProcessor {
Future<bool> processPayment(double amount) async {
print('微信支付处理支付:¥$amount');
await Future.delayed(Duration(seconds: 1));
return true;
}
Future<void> refund(String transactionId) async {
print('微信支付退款:$transactionId');
await Future.delayed(Duration(milliseconds: 500));
}
String getProviderName() => '微信支付';
}
// 使用接口进行多态
class PaymentService {
PaymentProcessor processor;
PaymentService(this.processor);
Future<void> makePayment(double amount) async {
print('使用${processor.getProviderName()}进行支付');
bool success = await processor.processPayment(amount);
if (success) {
print('支付成功!');
} else {
print('支付失败!');
}
}
}
//使用示例
void main(){
var alipayService = PaymentService(AlipayProcessor());
var wechatService = PaymentService(WechatPayProcessor());
alipayService.makePayment(99.99);
wechatService.makePayment(199.99);
}
💡 7.重要概念:implements vs extends 的区别
🤔 常见问题:使用implements时如何调用"父类"方法?
答案:implements不是继承关系,无法直接调用"父类"方法!
让我用生活场景来解释这个重要区别:
// 场景对比:雇佣关系 vs 师父关系
// 1. extends(继承)- 就像师父传授技艺
// 厨神
class MasterChef {
String name;// 姓名
int experience;// 经验
MasterChef(this.name, this.experience);
void cookBasicDish() {
print('$name使用基础技法烹饪');
}
void teachSkills() {
print('$name传授烹饪技巧');
}
void displayInfo() {
print('厨师:$name,经验:$experience年');
}
}
// 学徒
class Apprentice extends MasterChef {
String specialty;// 特长,特点
Apprentice(String name, int experience, this.specialty) : super(name, experience);
void cookBasicDish() {
// 可以调用父类方法!
super.cookBasicDish(); // 先用师父的基础技法
print('$name加入自己的$specialty特色');
}
void learnFromMaster() {
super.teachSkills(); // 调用师父的方法
print('$name学会了师父的技艺');
}
}
// 2. implements(实现接口)- 就像按合同工作
// 烹饪合同
abstract class CookingContract {
void cookBasicDish();
void displayInfo();
}
// 签了合同的厨师
class ContractChef implements CookingContract {
String name;
int experience;
ContractChef(this.name, this.experience);
void cookBasicDish() {
// 无法调用"父类"方法,因为没有父类!
// super.cookBasicDish(); // ❌ 错误!没有super
print('$name按照合同要求烹饪');
}
void displayInfo() {
print('合同厨师:$name,经验:$experience年');
}
}
🎯 8. 解决方案:如何在implements中复用代码
// 方案1:组合模式 - 雇佣助手
class KitchenHelper {
static void prepareIngredients() {
print('准备食材...');
}
static void cleanKitchen() {
print('清洁厨房...');
}
static void basicCooking(String chefName) {
print('$chefName使用标准烹饪流程');
}
}
// 聪明的厨师
class SmartChef implements CookingContract {
String name;
int experience;
SmartChef(this.name, this.experience);
void cookBasicDish() {
// 使用助手的方法
KitchenHelper.prepareIngredients();
KitchenHelper.basicCooking(name);
print('$name完成烹饪');
}
void displayInfo() {
print('智能厨师:$name,经验:$experience年');
}
void cookSpecialDish() {
KitchenHelper.prepareIngredients();
KitchenHelper.basicCooking(name);
print('$name制作特色菜肴');
KitchenHelper.cleanKitchen();
}
}
// 方案2:Mixin模式 - 技能包
mixin BasicCookingSkills {
void prepareIngredients() {
print('准备新鲜食材');
}
void seasonFood() {
print('调味食物');
}
void plateFood() {
print('精美摆盘');
}
void standardCookingProcess(String dishName) {
prepareIngredients();
print('烹饪$dishName');
seasonFood();
plateFood();
}
}
// 专业的厨师
class ProfessionalChef implements CookingContract with BasicCookingSkills {
String name;
int experience;
ProfessionalChef(this.name, this.experience);
void cookBasicDish() {
// 使用Mixin的方法
standardCookingProcess('基础菜肴');
print('$name完成基础菜肴制作');
}
void displayInfo() {
print('专业厨师:$name,经验:$experience年');
}
void cookGourmetDish() {
standardCookingProcess('美食');
print('$name制作高级美食');
}
}
// 方案3:工厂模式 - 标准化流程
class CookingProcess {
static void executeStandardProcess(String chefName, String dish) {
print('=== $chefName的标准烹饪流程 ===');
print('1. 检查食材质量');
print('2. 预处理食材');
print('3. 开始烹饪$dish');
print('4. 调味和装盘');
print('5. 质量检查');
print('=== 烹饪完成 ===');
}
static void executeAdvancedProcess(String chefName, String dish) {
executeStandardProcess(chefName, dish);
print('6. 添加特色装饰');
print('7. 温度和口感最终调整');
print('=== 高级烹饪完成 ===');
}
}
// 餐厅厨师
class RestaurantChef implements CookingContract {
String name;
int experience;
String restaurant;
RestaurantChef(this.name, this.experience, this.restaurant);
void cookBasicDish() {
CookingProcess.executeStandardProcess(name, '招牌菜');
}
void displayInfo() {
print('餐厅厨师:$name,经验:$experience年,餐厅:$restaurant');
}
void cookSignatureDish() {
CookingProcess.executeAdvancedProcess(name, '$restaurant特色菜');
}
}
// 使用示例
void main(){
// 方案1:组合模式
print('方案1:组合模式');
var smartChef = SmartChef('小红', 5);
smartChef.displayInfo();
smartChef.cookBasicDish();
smartChef.cookSpecialDish();
print('\n方案2:Mixin模式');
var professionalChef = ProfessionalChef('小刚', 8);
professionalChef.displayInfo();
professionalChef.cookBasicDish();
professionalChef.cookGourmetDish();
print('\n方案3:工厂模式');
var restaurantChef = RestaurantChef('小丽', 10, '五星酒店');
restaurantChef.displayInfo();
restaurantChef.cookBasicDish();
restaurantChef.cookSignatureDish();
}
💡 总结:implements时复用代码的三种方案
-
组合模式:创建工具类,在实现类中调用
- 优点:简单直接,代码复用性好
- 缺点:需要显式调用,可能会忘记
-
Mixin模式:使用mixin提供通用功能
- 优点:自动获得功能,使用方便
- 缺点:可能会有命名冲突
-
工厂模式:标准化流程,统一调用
- 优点:流程标准化,易于维护
- 缺点:灵活性相对较低
🎯 选择建议:
- 简单场景:使用组合模式
- 复杂功能:使用Mixin模式
- 标准流程:使用工厂模式
更多推荐



所有评论(0)