Advanced Patterns
Advanced entity patterns in v3: polymorphism, inheritance, generics, and self-referencing types.
Sealed Classes & Polymorphism
Basic Sealed Class
Create a sealed abstract class for exhaustive pattern matching:
zfa entity create -n PaymentMethod --sealed
Generated:
()
abstract class $$PaymentMethod {
// Sealed class - can't be instantiated directly
}
Sealed Class with Implementations
# Create the sealed base
zfa entity create -n Shape --sealed
# Create implementations
zfa entity create -n Circle \
--field radius:double \
--extends=$$Shape
zfa entity create -n Rectangle \
--field width:double \
--field height:double \
--extends=$$Shape
zfa entity create -n Triangle \
--field base:double \
--field height:double \
--extends=$$Shape
Generated:
()
abstract class $$Shape {}
(generateJson: true)
abstract class $Circle implements $$Shape {
double get radius;
}
(generateJson: true)
abstract class $Rectangle implements $$Shape {
double get width;
double get height;
}
(generateJson: true)
abstract class $Triangle implements $$Shape {
double get base;
double get height;
}
Exhaustive Pattern Matching:
String describeShape($$Shape shape) {
return switch (shape) {
$Circle() => 'Circle with radius ${shape.radius}',
$Rectangle() => 'Rectangle ${shape.width}x${shape.height}',
$Triangle() => 'Triangle with base ${shape.base}',
};
// Compiler ensures all cases are covered!
}
final circle = Circle(radius: 5.0);
print(describeShape(circle)); // Circle with radius 5.0
Sealed Class with Explicit Subtypes
Define subtypes in the base class:
zfa entity create -n Notification \
--sealed \
--subtype=$EmailNotification \
--subtype=$PushNotification \
--subtype=$SmsNotification \
--field recipient:String
zfa entity create -n EmailNotification \
--field subject:String \
--field body:String \
--extends=$$Notification
zfa entity create -n PushNotification \
--field title:String \
--field message:String \
--extends=$$Notification
zfa entity create -n SmsNotification \
--field phoneNumber:String \
--field text:String \
--extends=$$Notification
Generated with shared field:
(explicitSubTypes: [$EmailNotification, $PushNotification, $SmsNotification])
abstract class $$Notification {
String get recipient; // Shared field
}
(generateJson: true)
abstract class $EmailNotification implements $$Notification {
String get subject;
String get body;
// Inherits: recipient
}
Inheritance
Single Inheritance
# Create interface
zfa entity create -n Timestamped --non-sealed \
--field createdAt:DateTime \
--field updatedAt:DateTime?
# Create entity implementing interface
zfa entity create -n Article \
--field title:String \
--field content:String \
--extends=$Timestamped
Usage:
final article = Article(
title: 'My Article',
content: 'Content here...',
createdAt: DateTime.now(),
updatedAt: null,
);
// Access inherited fields
print(article.createdAt);
print(article.title);
Multiple Inheritance
# Create multiple interfaces
zfa entity create -n Timestamped --non-sealed \
--field createdAt:DateTime \
--field updatedAt:DateTime?
zfa entity create -n Identifiable --non-sealed \
--field id:String
zfa entity create -n Trackable --non-sealed \
--field createdBy:String \
--field updatedBy:String?
# Create entity implementing all
zfa entity create -n Post \
--field title:String \
--field content:String \
--extends=$Timestamped \
--extends=$Identifiable \
--extends=$Trackable
Generated:
()
abstract class $Post implements $Timestamped, $Identifiable, $Trackable {
String get title;
String get content;
// Inherits: id, createdAt, updatedAt, createdBy, updatedBy
}
Interface Methods
Add abstract methods to interfaces:
zfa entity create -n Validator --non-sealed
# Then implement manually in the concrete class
# The generated class will include the interface
Generics
Single Generic Type
zfa entity create -n Result \
--field success:bool \
--field data:T? \
--field errorMessage:String?
Usage:
// String result
final stringResult = Result<String>(
success: true,
data: 'Hello',
);
// User result
final userResult = Result<User>(
success: true,
data: User(name: 'John'),
);
// List result
final listResult = Result<List<Product>>(
success: true,
data: products,
);
Multiple Generic Types
zfa entity create -n KeyValuePair \
--field key:K \
--field value:V
Usage:
final pair1 = KeyValuePair<String, int>(key: 'age', value: 30);
final pair2 = KeyValuePair<int, String>(key: 1, value: 'one');
final pair3 = KeyValuePair<User, Address>(key: user, value: address);
Generic with Constraints
// Generated generic classes work with any type
zfa entity create -n Box \
--field value:T \
--field isActive:bool
Nested Generics
zfa entity create -n ApiResponse \
--field data:List<T>? \
--field total:int \
--field page:int
# Usage with nested generics
final response = ApiResponse<List<Product>>(
data: products,
total: 100,
page: 1,
);
Self-Referencing Types
Tree Structure
zfa entity create -n CategoryNode \
--field id:String \
--field name:String \
--field children:List<$CategoryNode>? \
--field parent:$CategoryNode?
Usage:
final electronics = CategoryNode(
id: '1',
name: 'Electronics',
parent: null,
);
final phones = CategoryNode(
id: '2',
name: 'Phones',
parent: electronics,
children: null,
);
final laptops = CategoryNode(
id: '3',
name: 'Laptops',
parent: electronics,
children: null,
);
// Add children to parent
electronics = electronics.copyWith(
children: [phones, laptops],
);
Graph Structure
zfa entity create -n Node \
--field id:String \
--field label:String \
--field connections:List<$Node>
Usage:
final node1 = Node(id: '1', label: 'Node 1', connections: []);
final node2 = Node(id: '2', label: 'Node 2', connections: []);
final node3 = Node(id: '3', label: 'Node 3', connections: []);
// Create connections
node1 = node1.copyWith(connections: [node2, node3]);
node2 = node2.copyWith(connections: [node1, node3]);
node3 = node3.copyWith(connections: [node1, node2]);
Doubly Linked List
zfa entity create -n ListNode \
--field value:int \
--field next:ListNode? \
--field prev:ListNode?
Usage:
final node1 = ListNode(value: 1, next: null, prev: null);
final node2 = ListNode(value: 2, next: null, prev: node1);
final node3 = ListNode(value: 3, next: null, prev: node2);
node1 = node1.copyWith(next: node2);
node2 = node2.copyWith(next: node3);
Polymorphic Collections
List of Sealed Class Types
zfa entity create -n Animal --sealed
zfa entity create -n Dog \
--field name:String \
--field breed:String \
--extends=$$Animal
zfa entity create -n Cat \
--field name:String \
--field indoor:bool \
--extends=$$Animal
zfa entity create -n Zoo \
--field name:String \
--field animals:List<$$Animal>
Usage:
final zoo = Zoo(
name: 'City Zoo',
animals: [
Dog(name: 'Buddy', breed: 'Golden Retriever'),
Cat(name: 'Whiskers', indoor: true),
Dog(name: 'Max', breed: 'Bulldog'),
],
);
// Pattern match on each animal
for (final animal in zoo.animals) {
print(switch (animal) {
Dog() => 'Dog: ${animal.name} (${animal.breed})',
Cat() => 'Cat: ${animal.name} (${animal.indoor ? 'indoor' : 'outdoor'})',
});
}
Advanced JSON Patterns
Nested JSON Structure
zfa entity create -n Config \
--field name:String \
--field metadata:Map<String,dynamic> \
--field settings:List<$Setting>
zfa entity create -n Setting \
--field key:String \
--field value:String \
--field enabled:bool
JSON:
{
"name": "app-config",
"metadata": {
"version": "1.0.0",
"environment": "production"
},
"settings": [
{"key": "theme", "value": "dark", "enabled": true},
{"key": "notifications", "value": "all", "enabled": true}
]
}
Recursive JSON
Self-referencing types serialize correctly:
zfa entity create -n Menu \
--field title:String \
--field icon:String? \
--field children:List<$Menu>?
# Serializes to recursive JSON structure
Mixin Pattern with Interfaces
# Create reusable behaviors
zfa entity create -n Serializable --non-sealed \
--field serializationVersion:int
zfa entity create -n Trackable --non-sealed \
--field createdAt:DateTime \
--field modifiedAt:DateTime?
zfa entity create -n SoftDeletable --non-sealed \
--field isDeleted:bool \
--field deletedAt:DateTime?
# Mix and match
zfa entity create -n User \
--field username:String \
--field email:String \
--extends=$Serializable \
--extends=$Trackable \
--extends=$SoftDeletable
zfa entity create -n Product \
--field name:String \
--field price:double \
--extends=$Serializable \
--extends=$Trackable \
--extends=$SoftDeletable
Factory Pattern with Sealed Classes
# Define result types
zfa entity create -n Result --sealed \
--subtype=$Success \
--subtype=$Error
zfa entity create -n Success \
--field data:String
zfa entity create -n Error \
--field errorCode:int \
--field errorMessage:String
# Usage in a function
Result<String> processInput(String input) {
if (input.isEmpty) {
return Error(errorCode: 400, errorMessage: 'Empty input');
}
return Success(data: input.toUpperCase());
}
// Handle with exhaustive pattern matching
void handleResult(Result<String> result) {
switch (result) {
case Success():
print('Success: ${result.data}');
case Error():
print('Error ${result.errorCode}: ${result.errorMessage}');
}
}
Type-Safe State Machine
zfa entity create -n AppState --sealed \
--subtype=$LoadingState \
--subtype=$DataState \
--subtype=$ErrorState
zfa entity create -n LoadingState
zfa entity create -n DataState \
--field data:List<$Product>
zfa entity create -n ErrorState \
--field error:String \
--field retryable:bool
Usage:
AppState currentState = LoadingState();
void render(AppState state) {
switch (state) {
case LoadingState():
print('⏳ Loading...');
case DataState():
print('✅ Data: ${state.data.length} products');
case ErrorState():
print('❌ Error: ${state.error}');
}
}
Best Practices
1. Use Sealed Classes for Exhaustive Checking
// ✅ Good - Compiler enforces exhaustiveness
PaymentMethod method = ...;
switch (method) {
case $CreditCard(): /* handle */
case $PayPal(): /* handle */
// All cases must be handled
}
2. Prefer Composition Over Deep Nesting
# ✅ Good - Flat structure with references
zfa entity create -n Order \
--field customerId:String \
--field customerAddressId:String
# ❌ Avoid - Too deep
zfa entity create -n Order \
--field customer:$Customer \
# where Customer has Address, which has Geo, etc.
3. Use Generics for Flexibility
# ✅ Good - Reusable
zfa entity create -n ApiResult \
--field success:bool \
--field data:T?
# Works with any type
final userResult = ApiResult<User>(...);
final productResult = ApiResult<Product>(...);
4. Document Self-Referencing Structures
// Always document expected usage
/// Tree structure of categories
///
/// Use [parent] to navigate up the tree
/// Use [children] to navigate down
/// Root nodes have [parent] == null
/// Leaf nodes have [children] == null or empty
(generateJson: true)
abstract class $CategoryNode {
String get id;
String get name;
List<$CategoryNode>? get children;
$CategoryNode? get parent;
}
What's Next?
- Real-World Examples - Complete working examples
- Field Types Reference - All supported field types
- CLI Commands - Complete command reference