Skip to content

Instantly share code, notes, and snippets.

@Luoyayu
Last active March 6, 2022 10:24
Show Gist options
  • Save Luoyayu/9889bb1d451ac78ff1973b177ed5f3e3 to your computer and use it in GitHub Desktop.
Save Luoyayu/9889bb1d451ac78ff1973b177ed5f3e3 to your computer and use it in GitHub Desktop.
Tour of Dart: A simple Mixin example about printer
/// Tour of Dart
/// A simple Mixin example about printer.
class Paper {
String sizeName = 'Paper';
// bool printable = false;
// Paper(this.sizeName, this.printable);
/// Here we don't care whether Paper can be printed,
/// and what can be printed may not be Paper, or film.
/// We use Mixin onto [Printable] and
/// unique [PaperPrinting] when the subclass inherits [Paper].
Paper(this.sizeName);
}
/// [Film] can also be printed.
class Film {
String sizeName = 'Film';
// bool printable = true;
}
/// Printable protocol:
/// caller must implement [callPrinter] in two ways:
/// 1. abstract class Printable { void callPrinter(); }
/// 2. mixin Printable { void callPrinter(); }
/// I think the first one is clearer, declared as an interface:
/// the object provided must be *extends* or *with* [Printable]
/// The second way is equivalent to a protocol:
/// the object provided must *with* [Printable]
abstract class Printable {
void callPrinter();
}
/// The function we want to define like:
void printContent(Printable user) {
user.callPrinter();
}
typedef Context = Map<String, dynamic>;
/// The successor to [PaperPrinting]
/// must inherit from [Paper] or implement the related protocol,
/// which is equivalent to *where* in *Swift*
/// *on* [Printable] is optional, but declaring it helps to display overloads.
mixin PaperPrinting on Paper, Printable {
bool printable = true;
/// Print management [Context]
Context ctx = {};
/// Printable protocol: [callPrinter]
@override
void callPrinter() {
var printerId = applyPrinter(ctx);
sendTaskToPrinter(ctx, printerId, prepareContent());
taskFinishCallback(ctx);
}
// General process: apply for printer queue protocol
int applyPrinter(Context ctx) {
// ... system call for printer queue.
var printerId = 0x666;
ctx['applied'] = true;
ctx['printer_id'] = printerId;
return printerId;
}
/// General process: send task to printers
void sendTaskToPrinter(Context ctx, int printerId, String content) {
// ... Completed a series of tasks.
/// Update state of printer's context
ctx.putIfAbsent('finished', () => true);
}
/// The content to be printed is provided by the subclass
String prepareContent();
/// Callback function is provided by subclass
void taskFinishCallback(Context ctx);
}
class DraftPaper extends Paper {
DraftPaper({String sizeName = 'Draft Paper'}) : super(sizeName);
}
/// The order of *with*
/// the latter and the definition body provide the implementation for the former.
/// [PaperPrinting] in [PhotoPaper] implements the necessary [callPrinter].
class PhotoPaper extends Paper with Printable, PaperPrinting {
PhotoPaper({String sizeName = 'A6 Photo Paper'}) : super(sizeName);
@override
String prepareContent() => "...Content...";
@override
void taskFinishCallback(ctx) {
print(ctx['finished'] as bool
? "printing service using $sizeName."
: "May I try printer again?");
}
}
mixin FilmPrinting on Film, Printable {
@override
void callPrinter() => print('???');
}
/// we can implement [callPrinter] directly in [ExampleFilm] inherited from [Film]
class ExampleFilm extends Film with Printable {
@override
void callPrinter() => print("printing service using Example Film.");
}
void test() {
printContent(PhotoPaper());
printContent(ExampleFilm());
// ERROR: 'DraftPaper' can't be assigned to 'Printable'.
// printContent(DraftPaper());
/* Output:
printing service using A6 Photo Paper.
printing service using Example Film.
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment