DART2 Prima Plus - 教程 4 - OOPS
DART 中的面向对象编程
引言
在本文中,我将讨论 DART 语言支持的面向对象编程特性。虽然它不像 C++、C# 等当前或以往的市场领导者那样完善,但它提供了足够的工具集/概念,让程序员在编程时感到舒适。
背景
几乎所有程序员都同意 OOP 由这四项基本原则构成,我将结合 DART 语言来探讨这一点。
抽象
:DART 只支持两种数据访问级别:public
和private
,没有经典的protected
。要将任何函数或变量定义为private
,请使用_
(下划线
)。封装
:在这一原则上,DART 与其他语言类似,它也提供了一个“壳”(class
)来封装数据和业务逻辑。多态
:多态分为两个概念。编译时多态
:DART 不支持函数重载,但支持运算符重载。运行时多态
:DART 使用@override
关键字支持函数重写。
继承
- DART 只支持使用extends
关键字的单层或多层继承。虽然它不支持多重继承,但您可以使用implements
关键字将多个类合并到一个类中。
我将通过一些代码来讨论每个要点,让我们开始这段旅程吧。
Using the Code
任务#1:抽象与封装
如前所述,抽象有两种数据访问级别:private
和 public
。默认情况下,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。
关注点
- 语言规范:http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf
- Dart 网站:https://dart.ac.cn/
- 文章 GitHub: https://github.com/thatsalok/FlutterExample/tree/master/dart4_oops
Flutter 教程
- Flutter 入门:教程 #1
- Flutter 入门:
教程 2 – StateFulWidget - Flutter 入门:教程 3 导航
- Flutter 入门:
教程 4 ListView - Flutter 入门:
教程 5 Grid
DART 系列
历史
- 2018 年 7 月 31 日 - 第一版