betacode

Методы в Dart

  1. Что такое метод?
  2. Регулярный метод
  3. Статический метод
  4. Абстрактный метод
  5. Дополнительные параметры
  6. Опциональные мменованные параметры
  7. Переопределение метода
  8. Final method?

1. Что такое метод?

В языке программирования Dart метод представляет собой блок кода (block of code), который определен внутри класса и запускается только при вызове. Методы разделяют большую задачу на мелкие части и выполняют определенную операцию программы. Этот процесс повышает возможность повторного использования кода и расширяет модульный подход программы.
В основном методы делятся на 3 типа:
  • Регулярный метод (нестатический и неабстрактный).
  • Статический метод (static method).
  • Абстрактный метод (abstract method).

2. Регулярный метод

Синтаксис для определения регулярного метода:
return_type method_name(arguments)    {  
     // statement(s)  
}
  • return_type: Возвращаемый тип данных метода. Используйте ключевое слово void в качестве типа возвращаемого значения, если метод ничего не возвращает.
  • method_name: Имя метода. В отличие от других языков, таких как Java, Dart не допускает двух методов с одинаковым именем, даже если они имеют разные параметры. Это необходимо для преобразования кода Dart в JavaScript.
  • arguments: Параметры метода.
Например: класс Cat и его метод sayHello(..). Чтобы вызвать sayHello(..), необходимо создать объект Cat и вызвать метод, используя точечную нотацию (dot notation).
method_ex1.dart
class Cat {
  void sayHello(String name) {
    print("Hello $name");
  }
}
void main() {
  Cat tom = new Cat(); // Create a Cat object.  
  tom.sayHello("Jerry"); // Call the method through the object.
}
Output:
Hello Jerry
Метод может содержать 0, 1 или более параметров, разделенных запятыми.
method_ex2.dart
class Rectangle {
  int width;
  int height;
  Rectangle(this.width, this.height); // Constructor

  int getArea() {
    return width * height;
  }
  void changeWidthHeight(int newWidth, int newHeight)  {
      width = newWidth;
      height = newHeight;
  }
  void showMe()  {
     print('I am a rectangle, width: $width, height: $height');
  }
}
void main() {
   Rectangle rec = Rectangle(5, 10); // Create an object.
   
   rec.showMe();  // Call the method.
   var area = rec.getArea();  // Call the method.
   print('Area: $area');
   print(' --- Change width and height --- ');
   rec.changeWidthHeight(25, 15); // Set newWidth, newHeight
   rec.showMe(); // Call the method.  
   area = rec.getArea(); // Call the method.
   print('Area: $area');
}
Output:
I am a rectangle, width: 5, height: 10
Area: 50
--- Change width and height ---
I am a rectangle, width: 25, height: 15
Area: 375

3. Статический метод

Dart использует ключевое слово static и синтаксис определения обычного метода для определения статического метода.
Синтаксис для определения статического метода:
static return_type method_name(arguments)    {  
     // statement(s)  
}
Характеристики статического метода:
  • Статический метод вызывается через имя класса и точечную нотацию. Например, MyUtility.sum(100, 50). Имя класса и точечная нотация могут быть опущены, если вы вызываете статический метод внутренне.
  • Нестатические члены класса не могут отображаться в статическом методе, если к ним не осуществляется доступ через объект (см. Пример ниже).
method_static_ex1.dart
class MyUtility {
  static int sum(int a, int b)  {
    return a + b;
  }
  static int minus(int a, int b)  {
    return a - b;
  }
}
void main() {
   var result = MyUtility.sum(100, 50);
   print('Sum Result: $result');
   result = MyUtility.minus(100, 50);
   print('Minus Result: $result');
}
Output:
Sum Result: 150
Minus Result: 50
Затем посмотрите на приведенный ниже пример:
  • side1, side2 и side3 являются нестатическими полями (field) класса Triangle, которые не могут отображаться в статическом методе.
  • Для вызова статического метода в определенном классе может не потребоваться имя класса и точечная нотация.
method_static_ex2.dart
class Triangle {
  late double side1;
  late double side2;
  late double side3;
  static const String DEFAULT_COLOR  = 'blue'; // Static field

  Triangle(double s1, double s2, double s3) {
    bool valid = isValidSides(s1, s2, s3); // Check if all sides are valid.
    if(!valid) {
      throw ArgumentError('Invalid Sides!'); // Throw an Error.
    }
     side1 = s1;
     side2 = s2;
     side3 = s3;
  }
  static bool isValidSides(double s1, double s2, double s3)  {
     if(s1 < 0 || s2 < 0 || s3 < 0)  {
       return false;
     }
     return s1 + s2 > s3 && s1 + s3 > s2 && s2 + s3 > s1;
  }
  bool isEquilateralTriangle() {
      return side1 == side2 && side2 == side3;
  }
}
void main() {
   bool valid = Triangle.isValidSides(6, 8, 10);
   print('Are sides 6, 8 and 10 valid to make a triangle? $valid');
   var triangle = Triangle(3.0, 4.0, 5.0);
   // Check if the triangle is equilateral triangle.
   var check = triangle.isEquilateralTriangle();
   print('Is Equilateral Triangle? $check');
}
Output:
Are sides 6, 8 and 10 valid to make a triangle? true
Is Equilateral Triangle? false

4. Абстрактный метод

В языке Dart абстрактный метод является нестатическим методом и не имеет тела (body).
abstract return_type method_name(arguments);
Класс с хотя бы одним абстрактным методом должен быть объявлен абстрактным. Один из его подклассов переопределит (override) абстрактные методы и напишет для них контент.
Например: Класс Person ниже должен быть объявлен как абстрактный класс, потому что он имеет по крайней мере один абстрактный метод.
method_abstract_ex1.dart
abstract class Person {
  void sayHello(); // An abstract method.
}
class EnglishPerson extends Person {
  void sayHello() {
    print("Hello");
  }
}
class RussianPerson extends Person {
   void sayHello() {
      print("Привет");
   }
}
void main() {
    Person enPerson = EnglishPerson();
    enPerson.sayHello();
    Person ruPerson = RussianPerson();
    ruPerson.sayHello();
}
Output:
Hello
Привет
  • Dart Classes

5. Дополнительные параметры

Как упоминалось выше, классы в Dart и JavaScript не поддерживают методы с одинаковыми именами, но метод может включать необязательные параметры.
Синтаксис:
// Non-static method with optional arguments:
return_type method_name(typeM argM, typeN argN,[typeP? argP, typeQ? argQ]){  
     // statement(s)  
}
// Static method with optional arguments:
static return_type method_name(typeM argM, typeN argN,[typeP? argP, typeQ? argQ]){   
     // statement(s)  
}
// Abstract method with optional arguments:
return_type method_name(typeM argM, typeN argN,[typeP? argP, typeQ? argQ]);
Или синтаксис - Необязательные параметры со значениями по умолчанию:
// Non-static method with optional arguments:
return_type method_name(typeM argM, typeN argN,
                        [typeP? argP = defaultValueP, typeQ? argQ]){  
     // statement(s)  
}
// Static method with optional arguments:
static return_type method_name(typeM argM, typeN argN,
                        [typeP? argP = defaultValueP, typeQ? argQ]){   
     // statement(s)  
}
// Abstract method with optional arguments:
return_type method_name(typeM argM, typeN argN,
                        [typeP? argP = defaultValueP, typeQ? argQ]);
Например:
method_optional_args_ex1.dart
class MyUtility {
  static String concat(String s1, String s2, [String? s3]) {
    if (s3 != null) {
      return s1 + s2 + s3;
    }
    return s1 + s2;
  }
  static double sum(double v1, double v2, [double? v3, double? v4]) {
    return v1 + v2 + (v3 ?? 0) + (v4 ?? 0);
  }
}
void main() {
  String result1 = MyUtility.concat('One', 'Two');
  print('result1: $result1');
  String result2 = MyUtility.concat('One', 'Two', 'Three');
  print('result2: $result2');
  double value1 = MyUtility.sum(1, 2, 3, 4);
  print('value1: $value1');
  double value2 = MyUtility.sum(1, 2, 3);
  print('value2: $value2');
  double value3 = MyUtility.sum(1, 2);
  print('value3: $value3');
}
Output:
result1: OneTwo
result2: OneTwoThree
value1: 10.0
value2: 6.0
value3: 3.0
Например:
method_optional_args_ex2.dart
class Team {
   List<String> members = [];

   void addMembers(String member1, [String? member2, String? member3]) {
      members.add(member1);
      if(member2!= null) {
         members.add(member2);
      }
      if(member3!= null) {
         members.add(member3);
      }
   }
   void printAllMembers()  {
      print(' --- All members: --- ');
      for(var member in members) {
          print(member);
      }
   }
}  
void main() {
  var team = Team(); // Create Team object.
  team.addMembers('Tom', 'Jerry');
  team.printAllMembers();
}
Output:
--- All members: ---
Tom
Jerry

6. Опциональные мменованные параметры

Опциональные именованные параметры (Optional Named Parameters) - это параметры, заключенные в фигурные скобки {} и являющиеся последними параметрами в списке параметров. Все эти параметры имеют значения по умолчанию.
Синтаксис:
// Non-static method with optional named parameters:
return_type method_name(typeM argM, typeN argN,
                  {typeP paramP = defaultValueP, typeQ paramQ = defaultValueQ}){  
     // statement(s)  
}
// Static method with optional arguments:
static return_type method_name(typeM argM, typeN argN,
                  {typeP paramP = defaultValueP, typeQ paramQ = defaultValueQ}){  
     // statement(s)  
}
// Abstract method with optional arguments:
return_type method_name(typeM argM, typeN argN,
                  {typeP paramP = defaultValueP, typeQ paramQ = defaultValueQ});
Например:
method_optional_named_args_ex1.dart
class StringUtility {
  static String concatAndTrim(String s1, String s2, {bool trimLeft = true, bool trimRight = true}) {
    var s = s1 + s2;
    if (trimLeft && trimRight) {
      return s.trim();
    } else if (trimLeft) {
      return s.trimLeft();
    } else if (trimRight) {
      return s.trimRight();
    }
    return s;
  }
}
void main() {
  var s1 = '  One  ';
  var s2 = '  Two  ';
  var result1 = StringUtility.concatAndTrim(s1, s2); // trim left and right
  print('result1: -->$result1<-- (Trim left and right)');

  var result2 = StringUtility.concatAndTrim(s1, s2, trimLeft: false); // trim right only
  print('result2: -->$result2<-- (Trim right only)');

  var result3 = StringUtility.concatAndTrim(s1, s2, trimRight: false); // trim left only
  print('result3: -->$result3<-- (Trim left only)' );

  var result4 = StringUtility.concatAndTrim(s1, s2, trimLeft: false, trimRight: false); // no trim
  print('result4: -->$result4<!-- (No Trim)');
}
Output:
result1: -->One    Two<-- (Trim left and right)
result2: -->  One    Two<-- (Trim right only)
result3: -->One    Two  <-- (Trim left only)
result4: -->  One    Two  <!-- (No Trim)

7. Переопределение метода

Подкласс может переопределять (override) метод родительского класса, если выполняются следующие условия:
  • Два метода должны иметь одинаковое имя и одинаковые параметры.
  • Тип возвращаемого значения двух методов должен быть одинаковым или тип возвращаемого значения метода в подклассе должен быть подтипом типа возвращаемого значения метода в родительском классе.
Например:
  • Класс Cat переопределяет (override) метод sayAnything() класса Animal.
  • @override - это опциональная аннотация (annotation), помещаемая перед переопределяемым методом (в подклассе). Если вы случайно переименуете этот метод в родительском классе, компилятор Dart выдаст вам сообщение об ошибке.
method_override_ex1.dart
class Animal {
  void sayAnything() {
    print('<Nothing>');
  }
}
class Cat extends Animal {
  @override
  void sayAnything() { // Override method from parent class.
    print('Meow');
  }
}
void main() {
  Animal animal = Cat();
  animal.sayAnything();
}
Output:
Meow
Например: Используйте ключевое слово super для вызова метода родительского класса.
method_override_ex2.dart
class BoldFormatter {
  String formatText(String text) {
    return '<b>' + text + '</b>';
  }
}
class BoldItalicFormatter extends BoldFormatter {
  @override
  String formatText(String text) { // Override method from parent class.
    var boldText = super.formatText(text); // Call super method.
    return '<i>' + boldText + '</i>';
  }
}
void main() {
  var formatter = BoldItalicFormatter();
  var formattedText = formatter.formatText('Hello');
  print(formattedText);
}
Output:
<i><b>Hello</b></i>

8. Final method?

В языке Java вы можете использовать ключевое слово final для метода, чтобы гарантировать, что подклассы не смогут переопределить (override) этот метод. Есть ли что-то подобное в Dart?
package:meta дает вам @nonVirtual, чтобы предотвратить переопределение подкласса методом родительского класса. Это помогает Analyzer (анализатору кода) сообщать об ошибке, если вы нарушаете это, но никаких других действий не предпринимается.
method_final_ex1.dart
import 'package:meta/meta.dart';

class Foo {
   @nonVirtual
   void bar() {
     print("bar from Foo!");
   }
}
class SubFoo extends Foo {
  @override
   void bar()  {
      print("bar from SubFoo");
   }
}
В принципе, вы получите предупреждение (warning) от Analyzer, которое выглядит следующим образом:
The member 'bar' is declared non-virtual in 'Foo'
and can't be overridden in subclasses.dart(invalid_override_of_non_virtual_member)
  • Thêm thư viện vào dự án Dart