在这里插入图片描述

面向对象编程就像建造房子,我们先设计图纸(类),然后按图纸建造房子(对象)。

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时复用代码的三种方案

  1. 组合模式:创建工具类,在实现类中调用

    • 优点:简单直接,代码复用性好
    • 缺点:需要显式调用,可能会忘记
  2. Mixin模式:使用mixin提供通用功能

    • 优点:自动获得功能,使用方便
    • 缺点:可能会有命名冲突
  3. 工厂模式:标准化流程,统一调用

    • 优点:流程标准化,易于维护
    • 缺点:灵活性相对较低

🎯 选择建议:

  • 简单场景:使用组合模式
  • 复杂功能:使用Mixin模式
  • 标准流程:使用工厂模式
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐