Chuyển đến nội dung chính

Bài đăng

Hiển thị các bài đăng có nhãn Patterns

Dependency injection in Flutter without the ceremony

Dependency injection has an intimidating name for an unremarkable idea: a class should be handed what it needs rather than constructing or locating it. That is the whole concept. Everything else — containers, locators, providers, generated code — is machinery for delivering it. The reason to care is testing. ApiClient() written inside a repository means every test of that repository makes real network calls. ApiClient passed in means every test can pass a fake. That is the entire payoff, and it is enough. Constructor injection, which needs no package final class UserRepository { const UserRepository ( this ._api, this ._cache); final ApiClient _api; final UserCache _cache; Future < User > fetch ( String id) async { final cached = _cache. get (id); if (cached != null ) return cached; final user = await _api. getUser (id); _cache. put (user); return user; } } Testing this requires no framework at all: test ( ...

Records and patterns in Dart: what they replace

Before records, returning two values from a function meant one of three unappealing options: a class you use once, a List<Object> you index into, or two out-parameters via a wrapper. Records make it one line. ({ int width, int height}) measure ( String text) { // ... return (width : 120 , height : 40 ); } final size = measure ( 'hello' ); print (size.width); That is the headline feature, and it is the smallest part of what records and patterns changed. Records: structural, not nominal A record’s type is its shape. (int, String) and (int, String) are the same type regardless of where they were created, which is what distinguishes a record from a class. // Positional ( String , int ) parseEntry ( String line) { final parts = line. split ( ':' ); return (parts[ 0 ], int . parse (parts[ 1 ])); } // Named — clearer at the call site ({ String name, int score}) parseNamed ( String line) { final parts = line. split ( ':...