65.9K
CodeProject 正在变化。 阅读更多。
Home

DART2 Prima Plus - 教程 4 - OOPS

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2018年7月31日

CPOL

5分钟阅读

viewsIcon

10603

downloadIcon

61

DART 中的面向对象编程

引言

在本文中,我将讨论 DART 语言支持的面向对象编程特性。虽然它不像 C++、C# 等当前或以往的市场领导者那样完善,但它提供了足够的工具集/概念,让程序员在编程时感到舒适。

背景

几乎所有程序员都同意 OOP 由这四项基本原则构成,我将结合 DART 语言来探讨这一点。

  • 抽象:DART 只支持两种数据访问级别:publicprivate,没有经典的 protected。要将任何函数或变量定义为 private,请使用 _下划线)。
  • 封装:在这一原则上,DART 与其他语言类似,它也提供了一个“壳”(class)来封装数据和业务逻辑。
  • 多态:多态分为两个概念。
    • 编译时多态:DART 不支持函数重载,但支持运算符重载。
    • 运行时多态:DART 使用 @override 关键字支持函数重写。
  • 继承 - DART 只支持使用 extends 关键字的单层或多层继承。虽然它不支持多重继承,但您可以使用 implements 关键字将多个类合并到一个类中。

我将通过一些代码来讨论每个要点,让我们开始这段旅程吧。

Using the Code

任务#1:抽象与封装

如前所述,抽象有两种数据访问级别:privatepublic。默认情况下,DART 类中的每个函数和变量都是 public 的。与 C# 和 C++ 等其他流行的 OOP 语言相比,在这些语言中,所有项默认都是 private 的。我认为原因可能是它更接近 JavaScript。

其次,DART 中没有 protected 关键字。下面是一个演示 **封装** 和 **抽象** 的小程序。在这里,我将类变量设为 private,请注意,为了使变量 private,我使用了 _(下划线)。对于 **封装**,我们创建类,它提供了一个“壳”来容纳变量和方法,并将变量的作用域限制在类对象生命周期内。

class AbstractionEncapsulation {

String title;

AbstractionEncapsulation(String argtitle) : title = argtitle {
print("in default constructor $title");
}

AbstractionEncapsulation.fromAnotherObject(
AbstractionEncapsulation abstEncap) {
this.title = abstEncap.title;
}

printTitle() {
print(title);
}

}

void testabstractionencapsulation() {

print("testabstractionencapsulation start");

AbstractionEncapsulation abstractionEncapsulation =
new AbstractionEncapsulation('hello');

AbstractionEncapsulation abstractionEncapsulation1 =
new AbstractionEncapsulation.fromAnotherObject(abstractionEncapsulation);

abstractionEncapsulation1.printTitle();
}

构造函数/析构函数

DART 中没有析构函数这个概念,因为它是一种垃圾回收语言。当类对象不再被引用时,它就会从内存中移除。由于(在撰写本文时)没有弱引用或指针的概念,DART 运行时会在对象不再被任何其他对象引用时管理内存移除。

DART 类中只能有一个默认/带参数的构造函数,其余的应该是命名构造函数。由于 DART 不支持方法重载,因此函数名必须不同,否则会收到编译时错误。大多数时候,DART 程序被设计为兼容 JavaScript,因此它从中借鉴了很多概念。由于它仍在发展中,希望将来它能支持函数重载。

任务#2:继承

在描述多态之前,我先解释一下 DART 中的继承。对于重写或运行时多态,我们需要继承。现在,如前所述,DART 使用 extends 支持单层和多层继承。虽然不支持多重继承,但您可以使用 implements 关键字将多个类实现到新类中。扩展和实现的主要区别在于,当您扩展时,您是在扩展类的功能(继承的主要特性);而当您实现时,您是从一个或多个类组合类。根据 DART 网站

引用

每个类都会隐式地定义一个接口,其中包含该类以及它所实现的所有接口的所有实例成员。如果您想创建一个类 A,它支持类 B 的 API 而不继承 B 的实现,那么类 A 应该实现 B 接口。

让我们看看如何在 DART 中实现单层继承。

abstract class Shape {

String get name;
set length(int ilen);
set breath(int ibre);
num getArea();
}

class Rectangle extends Shape {

int _length, _breath;

@override
set breath(int ibre) {
_breath = ibre;
}

@override
num getArea() {
return _length * _breath;
}

@override
set length(int ilen) {
_length = ilen;
}

@override
String get name => 'Rectangles';
}

testsingleinheritencedart() {

singleinheritencedart.Shape sh = new singleinheritencedart.Rectangle();
sh.breath = 10;
sh.length = 10;

print("the area of ${sh.name} is ${sh.getArea()}");

}

这段代码将展示 DART 中的多重继承。在这里,我创建了 circle 类,它实现了前一个示例中的 Shape 类和 ShapePerimeter

import 'package:dart4_oops/singleinheritence.dart';

abstract class ShapePerimeter {
  num getPerimeter();
}

class Circle implements ShapePerimeter, Shape {
  int _length;
  @override
  set breath(int ibre) {
    // TODO: implement breath
  }

  @override
  num getArea() {
    return (3.14 * _length * _length);
  }

  @override
  num getPerimeter() {
    return (2 * 3.14 * _length);
  }

  @override
  set length(int ilen) {
    _length = ilen;
  }

  // TODO: implement name
  @override
  String get name => 'Circle';
}

testmultipleinheritencedart() {
  singleinheritencedart.Shape sh = new multipleinheritencedart.Circle();

  sh.length = 10;

  multipleinheritencedart.ShapePerimeter sp =
      sh as multipleinheritencedart.Circle;

  print("the area of ${sh.name} is ${sh.getArea()}");
  print("the perimeter of ${sh.name} is ${sp.getPerimeter()}");
}

任务#3:多态

到目前为止,您已经了解了 DART 如何实现抽象、封装和继承。现在,让我们学习 OOP 的最后一个原则。多态的字面意思是“存在多种形式”。DART 的多态性不如其他语言广泛,但有很多变通方法可以达到类似的结果。首先,不支持方法重载,即:

以下代码在 DART 中将无法编译,这在 C++/C# 中用于演示方法重载的非常常见的情况。

void Overloading1(int a){}

void Overloading1(int a,int b){}

但是,可以使用 命名参数可选参数 来实现类似的功能(尽管这会使函数臃肿,并违反 **S**OLID 原则)。C# 支持命名参数和可选参数,而 C++ 只支持后者。对于可选参数,我们使用 [](方括号);命名参数则在 {}(花括号)中指定。

使用可选参数 - 使用命名参数

class Overloading {
  final int Price;
  Overloading({this.Price});
//using Optional Parameter
  int getTyrePrice(int iTyres, [int price]) {
    if (price != null) return iTyres * price;
    return iTyres * Price;
  }

//-- Using Named Parameter 
  String getTyreBrand(int price, {int multiple}) {
    int iprice = price;
    if (multiple != null) iprice *= multiple;

    if (iprice < 100)
      return "APOLLO TYRES";
    else if (iprice < 200)
      return "BRIDGESTONE ";
    else if (iprice < 500) return "MICHELIN ";
    return "Tyre not available";
  }
}

testOverloadingdart() {
  Overloading obj = new Overloading(Price: 100);
  print(obj.getTyrePrice(5));
  print(obj.getTyrePrice(5, 200));
  print(obj.getTyreBrand(150));
  print(obj.getTyreBrand(90, multiple: 3));
}

然而,如果不支持函数重载,也不要灰心,DART 支持运算符重载。以下是 DART 网站 上可重载运算符的列表。

可重载运算符

< + | []
> / ^ []=
<= ~/ & ~
>= * << ==
% >>  

让我们通过一些代码来演示这一点,我将重载 + 运算符。

class OperatorOverload {
  int value = 0;

  operator +(int i) {
    this.value += i;
  }
}

void testOperatorOverload() {
  OperatorOverload oo = new OperatorOverload();
  print("initial value ${oo.value}");
  oo.value += 10;
  print("new value ${oo.value}");
}

至此,编译时多态部分完成,让我们深入探讨使用继承和重写的运行时多态。

附加:工厂构造函数

这是 DART 中引入的一种独特的构造函数类型。首先,factory 关键字只能用于构造函数。您可以使用它来创建单例和工厂模式类。这里,让我们直接通过代码来更好地理解它。

基于工厂构造函数的单例模式:虽然它不满足单例模式的第一个条件,即使构造函数 private,但我满足了控制对象创建的第二个条件。

class Singleton {
  static Singleton _objSingleton;
  String _information;

  String get Information => _information;
  set Information(String info) {
    _information = info;
  }

  Singleton() {}

  factory Singleton.Me() {
    if (_objSingleton == null) _objSingleton = new Singleton();
    return _objSingleton;
  }
}

void testSingleton() {
  Singleton singleton = new Singleton.Me();
  singleton.Information = "Information from first Object";
  print("From singleton object :" + singleton.Information);

  Singleton singleton1 = new Singleton.Me();
  print("From singleton1 object :" + singleton1.Information);
}

注意:Dart 目前只支持单线程,因此 DART 中没有锁定或互斥锁的概念,这在 C#/C++ 代码中创建单例对象时很常见,其中添加了线程同步代码只是为了确保对象只创建一次。

基于工厂构造函数的工厂模式:我使用 abstract 类和工厂构造函数,确保了我需要的对象类型。

enum EAnimal { Lion, Cat }

abstract class Animal {
  Animal() {}
  factory Animal.GetAnimal(EAnimal animal) {
    switch (animal) {
      case EAnimal.Lion:
        return new Loin();
      case EAnimal.Cat:
        return new Cat();
      default:
        return null;
    }
  }

  String SayHello();
}

class Cat extends Animal {
  @override
  String SayHello() {
    return "Cat say meow";
  }
}

class Loin extends Animal {
  @override
  String SayHello() {
    return "Loin Roar";
  }
}

void testFactoryPattern() {
  print(new Animal.GetAnimal(EAnimal.Lion).SayHello());
  print(new Animal.GetAnimal(EAnimal.Cat).SayHello());
}

至此,本教程结束。感谢您的阅读,请分享您的评论。您也可以通过 Twitter 联系我,我的句柄是 @thatsalok

关注点

Flutter 教程

  1. Flutter 入门:教程 #1
  2. Flutter 入门:教程 2 – StateFulWidget
  3. Flutter 入门:教程 3 导航
  4. Flutter 入门:教程 4 ListView
  5. Flutter 入门:教程 5 Grid

DART 系列

  1. DART2 Prima Plus - 教程 1
  2. DART2 Prima Plus - 第二课 - LIST
  3. DART2 Prima Plus - 第三课 - MAP

历史

  • 2018 年 7 月 31 日 - 第一版
© . All rights reserved.