Dart: Use mixin to outsource implementations for abstract methods - dart

my Goal is to structure my code with this. The Idea is to outsource an inplementation to elsewhere, so that your main class is not so overloaded with way to much methods. Mixins seamed to be perfect for that!
Example:
abstract class Animal {
String printAllPropeties();
}
class Elephant extends Animal {
Trunk trunk; // Trunk: some Datastructure
#override
String printAllPropeties() => trunk.toString();
}
class Bird extends Animal {
Wing wing; // Wing: some Datastrukture
#override
String printAllPropeties() => wing.toString();
}
But now I want to outsource printAllPropeties() to a mixin for each class:
abstract class Animal {
String printAllPropeties();
}
class Elephant extends Animal with ElephantAllPropeties {
Trunk trunk; // Trunk: some Datastructure
}
mixin ElephantAllPropeties on Elephant {
#override
String printAllPropeties() => trunk.toString();
}
class Bird extends Animal with BirdAllPropeties {
Wing wing; // Wing: some Datastrukture
}
mixin BirdAllPropeties on Bird {
#override
String printAllPropeties() => wing.toString();
}
But this would not work like it is now, because the mixin would implement itself.
So is there another way, or is it simply not possible, or possible with other methods??

Related

Dart: how to override a generic method?

Consider my following base class:
abstract class IChat<Message extends IMessage> {
String get getId;
List<T> getUsers<T extends IUser>();
}
Now my extended Model looks like this:
class Chat extends IChat<ChatMessage> {
String id;
List<ChatUser> members;
Chat({this.chat, this.members});
#override
String get getId => id;
#override
List<T> getUsers<T extends IUser>() => members;
}
List<T> getUsers<T extends IUser>() => members; throws an error because I return List<ChatUser> instead of List<T>. How do I override the method to make this work? My ChatUser class obviously also extends IUser.
Edit
#jamesdlin gave one solution: #override List<T> getUsers<T extends IUser>() => members.cast<T>(). It is possible without type casting?
First consider what you actually want your classes to do.
It seems like the subclass has a specific type of IUser that it always wants to return, but a generic function takes its type argument per invocation. So, the type should probably be a property of the class, not of the invocation.
Consider:
abstract class IChat<Message extends IMessage> {
String get getId;
List<IUser> getUsers();
}
class Chat extends IChat<ChatMessage> {
String id;
List<ChatUser> members;
Chat({this.chat, this.members});
#override
String get getId => id;
#override
List<ChatUser> getUsers() => members;
}
Would that satisfy your needs?
As stylistic comments, your code is very C#-like, and doesn't look like Dart. I'd probably declare the classes as:
abstract class Chat<M extends Message> {
String get id;
List<User> get users;
}
class SomeChat extends Chat<ChatMessage> {
#override
final String id;
#override
List<ChatUser> users;
// ...
SomeChat({this.id, List<CharUser> members, ...}) : users = members;
// ...
}

How to create a base factory and override it on child class in Flutter

So I have a class like Question like bellow:
#JsonSerializable()
class Question {
String id;
String content;
Question({this.id, this.content});
factory Question.fromJson(Map<String, dynamic> json) =>
_$QuestionFromJson(json);
Map<String, dynamic> toJson() => _$QuestionToJson(this);
}
Please keep in mind that those _$QuestionFromJson and _$QuestionToJson comes from this library https://pub.dev/packages/json_serializable
Say I have many class like that which have a fromJson factory and a toJson method. I want to create a base class that contains those 2 method. A base model is easy for toJson as bellow:
abstract class BaseModel {
Map<String, dynamic> toJson();
}
But what about the factory method, I have no idea how to declare them then override it simply like:
#override
factory Question.fromJson(Map<String, dynamic> json) =>
_$QuestionFromJson(json);
EDIT:
My idea of using this is because I want to create a converter utility that I only need to pass in the class of the result like Converter.listFromJson<MyClass>(jsonString). For now, the helper is:
static List<T> listFromJson<T>(jsonString, Function mappingFunction) {
return myJsonMap.map(mappingFunction).cast<T>().toList();
}
so I have to map each item by passing the map function every time I use this helper method:
Converter.listFromJson<Question>(
jsonMap, (item) => Question.fromJson(item));
There'are a few more class that needs to be convert to the list like this. I want to reuse the method without the (item) => Question.fromJson(item) method part. That's why I want to create a base class that have the factory fromJson method so that I can use it in the converter
return myJsonMap.map((item) => BaseModel.fromJson(item)).cast<T>().toList();
then I just simply call
Converter.listFromJson<Question>(jsonMap);
Thank you for your time.
i don't know if i got you correctly, that's what i understood from your question
abstract class BaseModel{
BaseModel();
BaseModel.fromJson(Map<String,dynamic> json);
}
class Question extends BaseModel{
final String id;
final String name;
Question({this.id,this.name}): super();
#override
factory Question.fromJson(Map<String, dynamic> json) {
return Question(
id: json['id'],
name: json['name']
);
}
}
void main(){
Map<String,dynamic> json = {'id': "dsajdas",'name': 'test'};
Question question = Question.fromJson(json);
print('question: ${question.id}');
}
That was my approach but you can't do such a thing. There is a workaround by declaring .fromJson(json) in a variable. Look at my sample codes, hope you can get an idea.
class Categories {
final String id;
String name;
String image;
Categories({this.id, this.name, this.image});
Categories.fromJson(dynamic json)
: id = json['id'],
name = json['name'],
image = json['image'];
}
class CategoriesModel extends AppModel<Categories> {
List<Categories> list = [];
Function fromJson = (dynamic json) => Categories.fromJson(json);
}
class AppModel<T> {
List<T> list = [];
Function fromJson;
List<T> getList() {
if (this.list.isNotEmpty) return this.list;
List<dynamic> list = GetStorage().read('tableName');
list.forEach((data) {
this.list.add(fromJson(data));
});
return this.list;
}
}

Flutter: extend a class by having to implement a method

Since I have two similar classes, but with little differences in only one function, I want to create a base class that they will extend, but that will also force them to implement that specific function. To better explain this:
class A {
void print() {print "hello";}
void func (){}
}
class B extends A {
#override func(){
//TODO
}
}
you can use an abstract base class, that is the parent of both classes
abstract class Base {
void func();
}
class A extends Base{
#override
void func() {
}
}
class B extends Base {
#override
void func() {
}
}

Extending the base class of a flutter app

Being new to Dart, I am not sure how I could extend the class of my statefull widget. This is what one of my class looks like
class HomeState extends State<Home>
{
}
What I would like to do is to make the HomeState class inherit some methods from my custom class. Which would be something like this
class CustomClass
{
void DisplayBusyDialog()
{
......
}
}
I know in Dart like Java you cannot inherit from multiple class (unlike C++).
My question is what would I need to do to have HomeState inherit from CustomClass ? Will my custom class need to inherit from StatefulWidget and then have HomeState class extend CustomClass ? what about the template State how do I handle that in my custom Class? Any suggestions would be appreciated ..
What you'll want is mixin, which allows multiple "extends".
class Bar {
bar() {}
}
mixin Mixin {
foo() {}
}
class Foo extends Bar with Mixin {
hello() {
foo();
bar();
}
}
And if you need your mixin the access fields from the base-class:
mixin Mixin on Bar {
foo() {
bar();
}
}
According to Dart programming language, the mixins has the solution to extend multiple parent classes. Anyhow if you want to follow the traditional object-oriented concept you can create an abstract class with a generic type.
abstract class _BaseStatefulState<T extends StatefulWidget> extends State<T> {
_BaseStatefulState() {
// Parent constructor
}
void baseMethod() {
// Parent method
}
}
Your StatefulWidget should be extended from the base like below:
class _MainScreenState extends _BaseStatefulState<MainScreen> {}
Example StatefulWidget:
import 'package:flutter/material.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends _BaseStatefulState<MainScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text("Test")),
);
}
}
abstract class _BaseStatefulState<T extends StatefulWidget> extends State<T> {
_BaseStatefulState() {
// Parent constructor
}
void baseMethod() {
// Parent method
}
}
Source reference:
https://gist.github.com/aslamanver/e1360071f9caff009101eb190a38d4cb
Flutter mixin documentation:
https://dart.dev/guides/language/language-tour#adding-features-to-a-class-mixins

List property inheritance

The parser is complaining that the property inheritor .list is not subtype of ModelList.list, but LeadsGroup does inherit from Model.
Is this wrong? What is the correct way to do this?
My base class:
abstract class ModelList {
List<Model> get list;
set list(List<Model> n);
}
The inheritor:
class ListLeadsGroup extends ModelList {
List<LeadsGroup> list;
}
class LeadsGroup extends Model {
}
If you have code like
class Foo extends ModelList {}
ModelList ml = new ListLeadsGroup();
ml.list.add(new Foo());
ml.list is of type Model, therefore adding Foo should be legit.
But this very likely is not what you want.
This is why List<ListLeadsGroup> can't override List<Model>.
This should do what you want:
abstract class ModelList<T extends Model> {
List<T> get list;
set list(List<T> n);
}
class ListLeadsGroup extends ModelList<LeadsGroup> {
List<LeadsGroup> list;
}
class LeadsGroup extends Model {
}
just copied from Matan Lurey's comment on Gitter
import 'package:func/func.dart';
class ModelRegistry {
final _factories = <Type, Func0<Model>>{};
Model create(Type type) => _factories[type]();
void register(Type type, Model factory()) {
_factories[type] = factory;
}
}
main() {
var registry = new ModelRegistry();
registry.register(FooModel, () => new FooModel());
var foo = registry.create(FooModel);
}
found a solution using the new keyword covariant. Now the classes that extends ModelList can override the List<Model> list without warnings.
#serializable
abstract class ModelList extends ModifiedModel
implements Model {
Type get listType {
throw new UnimplementedError();
}
List<Model> get list;
set list(covariant List n);
}

Resources