callable 类
Dart的callable类的实例, 可以像函数一样被调用。听起来有点神秘,但一个示例即可揭开它的面纱。
// ex461.dart
class Greeter {
String call(String name) => 'Hello, $name!'; // 1
}
void main() {
var g = Greeter(); // 2
print(g('World')); // 3 Output: Hello, World!
print(g.call('Dart')); // 3a Hello, Dart!
}
Greeter
类中有一个名为call
的实例方法;g
是Greeter
的一个实例;- 将
g
当作函数来调用,实际上调用了实例方法g.call
。
Greeter
定义了一个名为 call
实例方法,像这样的类即 callable 类,其实例为 callable 对象。换句话说, call
实例方法让一个类变得 callable。
除了call()
实例方法外,callable类当然还能有其它的方法和字段。
// ex462.dart
class Greeter {
String call(String name) => 'Hello, $name!'; // 1
String hi(String name) => 'Hi, $name!'; // 2
}
void main() {
var g = Greeter(); // 3
print(g.hi('Auggie')); // 4 Output: Hi, Auggie!
}
此例中的callable类 Greeter
定义了一个普通的实例方法 hi
,这样的方法也被称为命名函数。
接下来看看callable类的应用场景。
有状态的函数
设想有一个函数,需要在多次调用之间维护其内部状态。比起使用全局变量或复杂的闭包,callable类显得更加简洁。
// ex463.dart
class Counter {
int _count = 0; // 1
int call() => ++_count; // 2
void reset() => _count = 0; //3
}
void main() {
final count = Counter();
print(count()); // Output: 1
print(count()); // Output: 2
count.reset();
print(count()); // Output: 1
}
Counter
类是一个计数器, 实例变量_count
代表计数,是Counter
的内部状态;call()
方法每调用一次,_count
的值就加1并更新后的值;reset()
方法将_count
重置为0。
有状态的回调
事件处理函数或回调函数,有时需要管理与事件相关的状态,这是calllable类的另一个用武之地。
// ex464.dart
class Button {
Function()? onClick; // 1
void click() => onClick?.call(); // 2
}
class Callback {
final String _context; // 3
Callback(this._context); // 4
void call() => print('$_context click'); // 5
}
void main() {
var btn = Button();
btn.onClick = Callback('Alice');
btn.click(); // Output: Alice click
btn.onClick = Callback('Bob');
btn.click(); // Output: Bob click
}
Button
类表示图形界面上的按钮,当按钮被点击时,执行回调函数onClick
;click
方法用来模拟按钮被按下,注意这里是如何调用onClick
函数的(见call
方法);Callback
是一个callable类,代表回调函数,它有内部状态_context
;- 这是
Callback
的构造函数; call()
方法即回调函数的具体实现。
策略模式
callable类可用来实现设计模式里的策略模式。
比如商场对不同等级的客户有不同的折扣。
classDiagram ShoppingCart o--> DiscountStrategy DiscountStrategy <|-- VipDiscount DiscountStrategy <|-- RegularDiscount DiscountStrategy <|-- NoDiscount class ShoppingCart { - discountStrategy + double calculatePrice(double originalPrice) } class DiscountStrategy { <<interface>> + double call(double originalPrice) }
// ex465.dart
abstract interface class DiscountStrategy {
double call(double originalPrice); // 1
}
class VipDiscount implements DiscountStrategy {
@override
double call(double originalPrice) => originalPrice * 0.20; // 2
}
class RegularDiscount implements DiscountStrategy {
@override
double call(double originalPrice) => originalPrice * 0.10; // 2a
}
class NoDiscount implements DiscountStrategy {
@override
double call(double originalPrice) => 0.0; // 2b
}
class ShoppingCart {
DiscountStrategy _discountStrategy; // 3
ShoppingCart(this._discountStrategy);
set discountStrategy(DiscountStrategy strategy) => // 3a
_discountStrategy = strategy;
double calculatePrice(double originalPrice) => // 4
originalPrice - _discountStrategy(originalPrice);
}
void main() {
const price = 100.0;
final cart = ShoppingCart(RegularDiscount());
print('Price with regular discount: \$${cart.calculatePrice(price)}');
// Output: Price with regular discount: $90.0
cart.discountStrategy = VipDiscount();
print('Price with vip discount: \$${cart.calculatePrice(price)}');
// Output: Price with vip discount: $80.0
cart.discountStrategy = NoDiscount();
print('Price with no discount: \$${cart.calculatePrice(price)}');
// Output: Price with no discount: $100.0
}
DiscountStrategy
是折扣策略的接口(interface);VipDiscount
、RegularDiscount
和NoDiscount
是3个具体的折扣策略,它们都实现(implements)了DiscountStrategy
;ShoppingCart
代表购物车,它聚合了一个DiscountStrategy
;calculatePrice
方法负责计算最终的价格(原价 - 折扣
);