betacode

Методы в Dart

View more Tutorials:

Сайт бесплатного изучения языков:
Следуйте за нами на нашей фан-странице, чтобы получать уведомления каждый раз, когда появляются новые статьи. Facebook

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
Привет
  • TODO Link?

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)

View more Tutorials: