вторник, 27 апреля 2021 г.

Composite

abstract class IShape {
  void getArea();
}

class Shape implements IShape {
  double area;

  Shape(this.area);

  @override
  void getArea() {
    print(area);
  }
}

class Rect extends Shape {
  double w, h;

  Rect(this.w, this.h) : super(w * h);
}

class Circle extends Shape {
  double radius;

  Circle(this.radius) : super(3.14 * radius * radius);
}

class Canvas implements IShape {
  var shapes = <IShape>[];

  @override
  void getArea() {
    for (var shape in shapes) {
      shape.getArea();
    }
  }
}

void main() {
  final canvas = Canvas();
  canvas.shapes = [
    Rect(5, 5),
    Circle(3),
  ];
  canvas.getArea();
}

воскресенье, 25 апреля 2021 г.

Template Method

abstract class SoundSystem {
  void makeSound() {
    print(getSound());
  }

  String getSound();
}

class DVDPlayer extends SoundSystem {
  @override
  String getSound() {
    return 'Play DVD disk';
  }
}

class Radio extends SoundSystem {
  @override
  String getSound() {
    return 'Play radio station';
  }
}

void main() {
  final systems = <SoundSystem>[
    DVDPlayer(),
    Radio(),
  ];

  for (var system in systems) {
    system.makeSound();
  }
}

Adapter

abstract class ITemperatureAdapter {
  String getTemperature();
}

class CelsiusAdapter implements ITemperatureAdapter {
  double cel;
  CelsiusAdapter(this.cel);

  @override
  String getTemperature() {
    return 'Fahrenheit: ${C2F(cel)}';
  }

  double C2F(double cel) {
    return (cel * 9 / 5) + 32;
  }
}

class FahrenheitAdapter implements ITemperatureAdapter {
  double far;
  FahrenheitAdapter(this.far);

  @override
  String getTemperature() {
    return 'Celsius: ${F2C(far)}';
  }

  double F2C(double far) {
    return (far - 32) * 5 / 9;
  }
}

void main() {
  printTemp(CelsiusAdapter(10));
  printTemp(FahrenheitAdapter(104));
}

void printTemp(ITemperatureAdapter adapter) {
  print(adapter.getTemperature());
}

суббота, 24 апреля 2021 г.

Singleton

//Classic way
class Manager1 {
  static Manager1? _instance; //null

  Manager1._internal() {
    print('new instance of Manager1 constructed');
  }

  static Manager1? getInstance() {
    _instance ??= Manager1._internal();
    return _instance;
  }
}


//Dart way
class Manager2 {
  static final Manager2 _instance = Manager2._internal();

  Manager2._internal() {
    print('new instance of Manager2 constructed');
  }

  factory Manager2() {
    return _instance;
  }
}


void main() {

  final m1 = Manager1.getInstance(); //new instance of Manager1 constructed
  final m2 = Manager1.getInstance();

  final m3 = Manager2(); //new instance of Manager2 constructed
  final m4 = Manager2();

}

вторник, 13 апреля 2021 г.

Asynchronous

//Dart is a single-threaded language.
//Future - promise to give you the value later.
void main() {

  //Callbacks
  print('Start'); //1
  Future<int>.delayed(Duration(seconds: 3), () => 7)
      .then(
        (value) => print('Value: $value'), //3
  )
      .catchError(
        (error) => print('Error: $error'),
  )
      .whenComplete(
    //run after value or error
        () => print('Ready!'), //4
  );
  print('End'); //2

  //async-await
  print('Start2'); //synchronous function
  main2(); //asynchronous function - promise to give you the value later.
  print('End2'); //synchronous function

  //try-catch - error handling
  print('Start3');
  main3();
  print('End3');

}

//asynchronous function
Future<void> main2() async {
  final value = await Future<int>.delayed(Duration(seconds: 2), () => 7);
  //the rest of the function won’t run until the future completes
  print('Value2: $value');
  print('Ready2!');
}

//try-catch - error handling
Future<void> main3() async {
  try {
    //throw Exception('error'); //error testing
    final value = await Future<int>.delayed(Duration(seconds: 1), () => 7);
    //the rest of the function won’t run until the future completes
    print('Value3: $value');
  } catch (error) {
    print(error);
  } finally {
    print('Ready3!'); //run after value or error
  }
}

понедельник, 12 апреля 2021 г.

OOP

//Inheritance, Interfaces, Polymorphism, mixins
void main() {

  //Inheritance, "is, is! (is not)"-operators
  //Only one class can be inherited
  final st1 = Student('Tom', 'USA', 'German');
  print('Type: ' + st1.runtimeType.toString());
  print('isObject: ' + (st1 is Object).toString());
  print('isPerson: ' + (st1 is Person).toString());
  print('isStudent: ' + (st1 is Student).toString());
  print('isNotTeacher: ' + (st1 is! Teacher).toString());
  final st2 = Student('Mike', 'UK', 'Math');
  final tch1 = Teacher('Fred', 'France', 'Art');

  //Polymorphism - A Student is a Person
  //But prefer composition over inheritance!
  //It’s more of what an object HAS,
  //than what an object IS.
  final persons = <Person>[st1, st2, tch1];
  for (var person in persons) {
    print(person);
  }

  //Abstract classes - can't instantiate
  //final sh1 = Shape(); //error!
  final sq1 = Square(size: 5);
  final cr1 = Circle(radius: 5);
  //Polymorphism - Square and Circle are Shapes
  final shapes = <Shape>[sq1, cr1];
  for (var shape in shapes){
    if (shape is Square){
      print('I am ${shape.runtimeType}! With size: ${shape.size}. My area is: ${shape.area()}');
    } else if (shape is Circle){
      print('I am ${shape.runtimeType}! With radius: ${shape.radius}. My area is: ${shape.area()}');
    } else {
      print('I am ${shape.runtimeType}! My area is: ${shape.area()}');
    }
  }

  //Interfaces
  //Many interfaces cam be inherited
  final iDrawable sp1 = Sprite();
  sp1.draw();
  (sp1 as iUpdatable).update(); //as - casting

  //Factory constructor -
  //to keep the implementation details separate from the business logic.
  //Nothing changes here
  final someSubClass = FactoryClass();
  someSubClass.interface();

  //Mixins
  //Many mixins cam be inherited
  final mDrawable sp2 = Sprite1();
  sp2.draw();
  (sp2 as mUpdatable).update();
  final mUpdatable ph1 = Physics();
  ph1.update();

  //Extension methods
  st1.hi();
  st2.hi();
  print(5.doubled);
  print('Monday is a workday: ${Days.Monday.isWorkDay}');

}

//Parent (super) class
class Person {
  Person(this.name, this.country);
  String name;
  String country;
  String get info => 'My name is $name, I am from $country.';

  @override
  String toString() => info;
}

//Inheritance, "extends" keyword
//override properties and methods, super
//Child (sub) class
class Student extends Person {
  Student(String name, String country, this.subject) : super(name, country);
  String subject;

  @override
  String get info => '${super.info} I am learning $subject.';
}
class Teacher extends Person {
  Teacher(String name, String country, this.subject) : super(name, country);
  String subject;

  @override
  String get info => '${super.info} I am teaching $subject.';
}

//Abstract classes
abstract class Shape {
  Point center = Point();
  double area(); //abstract method
}
class Square extends Shape {
  Square({required this.size});
  final double size;
  @override //implements abstract methods
  double area() => size * size;
}
class Circle extends Shape {
  Circle({required this.radius});
  final double radius;
  @override //implements abstract methods
  double area() => 3.14 * radius * radius;
}
class Point{
  int x = 0, y = 0;
}

//Interfaces, "implements" keyword
//When you extend GameObj, Sprite has access to any methods or variables in GameObj.
//If Sprite implements iDrawable and iUpdatable, Sprite must provide its own version
//of all methods and variables in iDrawable and iUpdatable.
class GameObj {
}
abstract class iDrawable { //Interface
  late Point center; //late - initialises when instantiates
  void draw();
}
abstract class iUpdatable { //Interface
  void update();
}
class Sprite extends GameObj implements iDrawable, iUpdatable {
  @override
  Point center = Point();
  @override
  void draw() { //need implementation
  }
  @override
  void update() { //need implementation
  }
}

//Factory constructor, can return subclass!!!
//to keep the implementation details separate from the business logic
//Changes live here
abstract class FactoryClass { //Interface - see to user
  factory FactoryClass() => SubClass1();
  //factory FactoryClass() => SubClass2();
  //factory FactoryClass() => SubClass3();
  void interface();
}
class SubClass1 implements FactoryClass { //Concrete class - hide from user
  @override
  void interface() {
    print('I am $runtimeType');
  }
}

//Mixins, "with" keyword
//You can use concrete or abstract class as a mixin,
//but "mixin" keyword indicates that...
mixin mDrawable { //this class can only be used as mixin
  void draw() {
    print('Default draw');
  }
}
mixin mUpdatable { //this class can only be used as mixin
  void update() {
    print('Default update');
  }
}
class Sprite1 extends GameObj with mDrawable, mUpdatable {
  //do not need implementation of the draw and update methods
}
class Physics extends GameObj with mUpdatable{
  //we can use realisation from mixin class
}

//Extension methods
//we can extend String, int, ...
//name MyExt is optional
extension _MyExt on Person {
  void hi(){
    print('Hi $name');
  }
}
extension on int {
  int get doubled {
    return this * this;
  }
}

enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
extension on Days {
  bool get isWorkDay {
    switch (this) {
      case Days.Monday:
      case Days.Tuesday:
      case Days.Wednesday:
      case Days.Thursday:
      case Days.Friday:
        return true;
      case Days.Saturday:
      case Days.Sunday:
        return false;
      default:
        throw Exception('Unknown weekday $this');
    }
  }
}

пятница, 9 апреля 2021 г.

Functional

//Higher order methods
//map(), where(), every(), reduce(), fold() and sort().
void main() {

  var numbers = [1, 2, 3, 4, 5];

  //map()
  var sq1 = [];
  for(var element in numbers){
    sq1.add(element * element);
  }
  print(sq1);

  final sq2 = numbers.map((element) => element * element).toList();
  print(sq2);

  //where() - filter
  var even1 = [];
  for(var element in numbers){
    if (element.isEven) {
      even1.add(element);
    }
  }
  print(even1);

  final even2 = numbers.where((element) => element.isEven).toList();
  print(even2);

  //every()
  bool? isGood1;
  for(var element in numbers){
    if (element == 3) {
      isGood1 = false;
      break;
    }
    isGood1 = true;
  }
  print(isGood1);

  final isGood2 = numbers.every((element) => element != 3);
  print(isGood2);

  //reduce()
  var sum1 = 0;
  for (var element in numbers) {
    sum1 += element;
  }
  print(sum1);

  final total1 = numbers.reduce((value, element) => value + element);
  print(total1);

  //fold()
  var strings = ['a', 'bb', 'ccc', 'dddd', 'eeeee'];
  var sum2 = 0;
  for (var element in strings) {
    sum2 += element.length;
  }
  print(sum2);

  final total2 = strings.fold(0, (value, element) => (value as int) + element.length);
  print(total2);

  //sort()
  var list1 = [3, 5, 1, 4, 2];
  list1.sort();
  print(list1);

  //Comparable
  var list2 = ['c', 'a', 'b'];
  list2.sort();
  print(list2);

  //Comparator
  var list3 = ['ccc', 'a', 'bb'];
  list3.sort((prev, next) => prev.length.compareTo(next.length));
  print(list3);

  //Custom Types
  var points = [Point(3, 1), Point(1, 3), Point(2, 2)];
  //Comparable
  points.sort();
  print(points);
  //Comparator
  points.sort((prev, next) => prev.y.compareTo(next.y));
  print(points);

  //reversed property
  var reversedNumbers = numbers.reversed.toList();
  print(reversedNumbers);

  //Combining methods
  final seven = numbers.where((element) => (element % 2) == 0)
      .where((element) => element == 4)
      .map((e) => e + 3).first;
  print(seven);

}

class Point implements Comparable<Point>{
  Point(this.x, this.y);
  final x;
  final y;

  @override
  bool operator ==(Object other) {
    return (other is Point) && other.x == x && other.y == y;
  }

  //Comparable
  //The function must return an integer.
  // If the result is negative, the first value will be placed before the second value.
  // Otherwise, the second value will appear before the first value in the sorted List.
  // If the result is 0, it means both values are equal in the ordering.
  @override
  int compareTo(Point other) {
    return x - other.x;
  }

  @override
  int get hashCode => x.hashCode ^ y.hashCode;

  @override
  String toString() {
    return 'Point (x: $x, y: $y)';
  }
}