Now that we've introduced well-designed classes, we need to discuss methods.
The class constructors, methods, mutators (setters), and operators remove some restrictions on the values that must be passed into their parameters .What will happen if an invalid parameter value is passed to a method? One possibility is that the method will fail with a confusing exception or worse it will succeed but with a wrong result. In any case, it's dangerous not check the parameters of a method before using them. The rule here is to check whether the parameter value is valid as soon as possible. The best place to do that is at the beginning of the method.
The Dart VM can work in a developer-friendly checked mode and a speed-obsessed production mode. We usually use the checked mode when developing our applications. One of the benefits of this mode is the dynamic assertion. We should use the assert
statement to check whether the parameters of the method are valid before using it. The Dart VM continues the program execution if the Boolean result of the dynamic assertion is true
, otherwise stops it. This is shown in the following code:
/** * Return sum of [a] and [b]. * It throws [AssertionError] if any of [a] or [b] equals null */ sum(int a, int b) { assert(a != null); assert(b != null); return a + b; }
We must check the validity of the parameters stored in the method for later use. Ignoring this can lead to problems later because an error associated with the parameter can be thrown in a completely different place, making it harder to trace its source. This has serious implications, especially in constructors.
Sometimes, it is important to validate the internal state of a class in the method and generate a special error, as shown in the following code. The typical errors are StateError
, RangeError
, and ArgumentError
.
class Car { double petrol; /** * Start engine. * That method throws [StateError] if petrol is null * or less than 5 liters. */ void startEngine() { if (petrol == null || petrol <= 5.0) { throw new StateError('Not enough petrol'), } } }
Here, we have a Car
class with the petrol
variable and the startEngine
method. The startEngine
method checks whether there is enough petrol to start the engine; otherwise, it throws an error.
So, now that we've defined well-designed classes, it's time to define well-designed methods. We must remember that methods are part of a class' interface and the following simple rules can make them easier to use and also less error-prone:
A car may have the following different types of engines:
// Engine interface abstract class Engine { void start(); } // Diesel engine class DieselEngine implements Engine { void start() { // ... } } // Carburetor engine class CarburetorEngine implements Engine { void start() { // ... } } // Car class Car { var engine; // Car may have any engine Car(Engine this.engine); }
It's better to pass the abstract Engine
class as a parameter of the constructor for the car to prevent any problems in future.
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
18.188.187.165