Học nhanh ngôn ngữ Dart (Flutter) nhờ ngôn ngữ Kotlin (Phần 4 / 5)
Bài đăng này đã không được cập nhật trong 4 năm
1. Lời mở đầu
Series này được viết nhằm mục đích giúp những bạn đã hiểu biết về ngôn ngữ Kotlin hoặc Java có thể học nhanh ngôn ngữ Dart để code Flutter. Nếu bạn chưa đọc những phần trước, bạn có thể đọc lại tại đây
2. Class
Class trong Dart khá giống Java. Quy ước đặt tên class cũng giống Kotlin. Dưới đây mình liệt kê các thành phần cơ bản của một class gồm property (Dart gọi là data), constructor, member funtions (hay còn gọi là method), biến static và hàm static.
- Muốn tạo biến hoặc hàm static thì thêm từ khóa static ở trước thôi
- Dòng code
User(this.id, this.name, this.age);
trong Dart nó tương đương với đoạn code này trong Kotlin
constructor(id: Int, name: String, age: Int) {
this.id = id
this.name = name
this.age = age
}
- Nếu trong Class mà bạn không khai báo bất cứ một constructor nào cả, sẽ có một constructor rỗng (không có param) mặc định được tạo trong class của bạn và một khi bạn đã tạo ra được 1 constructor có param rồi thì constructor rỗng này sẽ biến mất. Tức là với code trên mà gọi
var user = User();
sẽ lỗi vì không tìm thấy constructor. Cái này giống y Kotlin với Java.
3. Data class
Cũng sử dụng đoạn code trên. Nếu thử print đối tượng user: print(user);
ta sẽ nhận được output là Instance of 'User'
chứ không phải là User(id=1, name=Minh, age=18)
như ta vẫn thường gặp bên Kotlin. Lý do là vì:
Dart không có hỗ trợ
data class
như Kotlin.
Đắng (facepalm). Mà không hỗ trợ data class thì phải overide
hàm toString
một cách thủ công thôi.
Bây giờ thì output đã giống Kotlin rồi:
User(id=1, name=Minh, age=18)
4. Named constructors
Dart cho phép chúng ta đặt tên constructors để tạo ra nhiều hơn 1 constructor. Mình thử tạo ra 3 constructor:
Output:
User(id=1, name=Minh, age=18)
User(id=0, name=null, age=18)
User(id=30, name=null, age=18)
Vì mấy biến name
kia không có giá trị khởi tạo nên nó null
. Dễ hiểu ha
5. Redirecting constructors
Thuật ngữ này bên Dart nó giống Secondary constructors
bên Kotlin ấy. Nó giúp ta tạo 1 constructor từ một constructor khác trong cùng class.
6. Import
Import file
Dart xem mỗi file .dart
như 1 lib
riêng biệt. Điều đó có nghĩa là dù 2 file .dart
nằm trong 1 package bạn cũng phải dùng import
. Cái này khác Kotlin ha.
Bây giờ thử tạo ra 2 file .dart
. Trong file user.dart
mình tạo 1 class là User
. Trong file .dart còn lại mình sẽ tạo hàm main()
và khởi tạo đối tượng User. Kết quả Dart nó yêu cầu phải import 'user.dart';
Thử move file user.dart
vào 1 folder có tên là example
rồi xem kết quả. Bây giờ đường dẫn thư mục đã đổi thành import 'example/user.dart';
Import thư viện core của Dart
Import thư viện core của Dart. Cú pháp import 'dart:xxx'
. Ví dụ thư viện math: import 'dart:math'
Import lib từ dependency hoặc lib do mình code trong thư mục lib
Cú pháp: import 'package:file path'
. Ví dụ:
import 'package:english_words/english_words.dart';
import as
Giả sử như chúng ta có 2 lib là lib1 và lib2. Cả 2 lib đều có class Element thì chúng ta sẽ phân biệt bằng cách dùng import ... as ...
:
Import một phần của lib
Nếu chúng ta chỉ muốn lấy một phần trong lib, không muốn lấy tất cả. Có thể dùng show/hide
7. Access modifier
Trong Dart không có access modifier (public, private, protected, internal) như Kotlin hay Java. Default là public hết. Nếu bạn muốn tạo một biến, hàm hoặc constructor mà private thì thêm ký tự underscore _
trước cái tên.
Thử tạo thêm 1 file user.dart rồi tạo 1 class trong file này
class User {
var id;
var name;
// biến private
var _age;
// hàm private
void _printName() {
print(name);
}
bool duTuoiXemPhim() => _age >= 18;
}
Giờ qua file main.dart để code hàm main:
Các bạn thấy nó báo lỗi không. Vậy là mình không thể gọi đến biến _age
và hàm _printName()
vì nó đã private
8. Setter, getter
Đã có biến private thì cần phải có hàm setter, getter đúng không nào . Dart cung cấp cho chúng ta 2 keyword là set
và get
để làm điều này.
9. Factory constructor, Singleton
Dart cung cấp cho chúng ta factory
keyword để tạo ra 1 constructor đặc biệt, khi sử dụng constructor này để tạo đối tượng nó sẽ không tạo ra một đối tượng mới nếu nó thấy đã có một đối tượng có sẵn rồi. Nói ngắn gọn là nó hoạt động giống như Singleton Pattern vậy. Vậy mình sẽ thử dùng factory để tạo ra một class Singleton
.
class Singleton {
static final Singleton _singleton = Singleton._internal();
// factory constructor
factory Singleton() {
return _singleton;
}
// Như mình đã nói ở trên thì đây là private constructor
Singleton._internal();
}
Bây giờ thử test xem 2 đối tượng có cùng địa chỉ hay không?
void main() {
var s1 = Singleton();
var s2 = Singleton();
// hàm identical giúp ta so sánh cùng địa chỉ hay ko?. Giống toán tử === bên Kotlin
print(identical(s1, s2)); // in ra: true
}
10. Cascade notation
Cái này khá giống apply
trong Kotlin. Cú pháp: ..
Các bạn thấy Dart lỗi ở lệnh print không?. Đó là lý do vì sao mình nói là khá giống mà không nói giống hoàn toàn :v. ..
trong Dart nó chỉ gọi được instance method/property thôi còn hàm print
thì nó chịu. Vậy nên chỉ cần chỉnh lại như thế này là được:
11. Enum
Đặt tên Enum trong Dart cũng viết kiểu UpperCamelCase
như Kotlin (VD: TypeOfStudent
). Nhưng các enum values trong Dart viết style lowerCamelCase
(VD: goodStudent
), còn Kotlin viết chữ hoa kèm dấu _
(VD: GOOD_STUDENT
).
12. Abstract class
Abstract class nó cũng giống class bình thường thôi, cũng có constructor, method và các property. Chỉ khác ở chỗ là nó có thêm abstract method (phương thức không có body). VD:
13. Kế thừa
Dart không hỗ trợ đa kế thừa, tức là một class chỉ có thể có tối đa một class cha. Chúng ta sử dụng từ khóa extend
để kế thừa class cha. Class cha có thể là abstract class cũng có thể là class thường. Khi extend
abstract class, chúng ta bắt buộc phải overide lại các abstract method (phương thức không có body).
Dart không có phân biệt Interface
với Class
như Kotlin mà nó xem mỗi class chính là interface luôn. Như vậy một class có thể kế thừa một class khác bằng từ khóa implement
. Một class chỉ có thể extend
một class
nhưng có thể implement
nhiều class
khác. Trong Dart không có khái niệm final class
như Kotlin, có nghĩa là tất cả class đều có thể được kế thừa.
Vì Interface trong Kotlin là phương thức không thân nên khi override lại sẽ không bị duplicate code. Còn Dart thì code trong class Dog
bị duplicate code với class mà nó implement là Walkable
, Flyable
như trong ảnh mình có note. Nếu như bạn chỉ muốn tái sử dụng code của lớp Walkable
, Flyable
mà không muốn override lại một hàm giống y chang như vậy (duplicate) thì bạn sử dụng with
thay cho implements
.
with
Bây giờ mình sẽ ví dụ đoạn code có sử dụng cả extend
, implements
và with
:
Sử dụng with
bạn sẽ không bị ép buộc phải override hết function, property, có nghĩa là bạn thích thì bạn cũng có thể override lại còn không thì sẽ reuse lại code. Còn sử dụng implements
thì buộc phải override lại hết, có nghĩa là sẽ có trường hợp bị duplicate code như ví dụ trên của mình
Cái with
này trong Dart người ta gọi là Mixins
. Thuật ngữ này có thể khá lạ lẫm với bạn nên mình xin trích nguyên văn từ doc là:
Mixins are a way of reusing a class’s code in multiple class hierarchies.
Hiểu nôm na là một nơi cung cấp method và property cho lớp khác sử dụng mà không cần phải là cha cũng chúng.
mixin
Dart cung cấp thêm cho chúng ta từ khóa mixin
. Trong ví dụ Kế thừa ở trên, bạn thử replace class Walkable
bằng mixin Walkable
thì kết quả vẫn không đổi. mixin
khác class
thông thường ở chỗ:
mixin
không có constructor nên không thể tạo đối tượng.mixin
chỉ có thể sử dụng đểimplements
hoặcwith
chứ không thểextends
mixin
có thể giới hạn những class nào được phép sử dụng code của mình bằng từ khóamixin on
mixin on
Như mình đã nói ở trên, ta sử dụng mixin on để giới hạn những class nào được phép sử dụng code của mình.
Nhìn vào ảnh trên có thể dễ hiểu rằng:
mixin XOnA
chỉ được dành cho những class nào là con củaclass A
cụ thể làclass P
, tương tự như thế vớimixin YOnB
.class T
không được phép sử dụngmixin YOnB
vì nó không phải là con củaclass B
.class R
không được phép sử dụngmixin XOnA
vì nó không phải là con củaclass A
. Chính xác thìclass R
là con củaclass Object
nên sửa lại thế này sẽ ok:
14. Override toán tử
Trong Kotlin, mỗi class cho phép ta override hàm equal
thì Dart overide toán tử ==
Ngoài toán tử ==
, bạn cũng có thể override các toán tử khác trong bảng sau nếu muốn
Kết luận
Đến giờ phút này đây thì các bạn đã có thể code Dart được rồi đấy . Hy vọng các bạn tiếp tục theo dõi những phần tiếp theo
Tham khảo: https://dart.dev/guides
https://medium.com/@manoelsrs/dart-extends-vs-implements-vs-with-b070f9637b36
Đọc tiếp phần 5: Học nhanh ngôn ngữ Dart (Flutter) nhờ ngôn ngữ Kotlin (Phần 5)
All rights reserved