Declare a variable to store an object that is only constructed with a specific named constructor in dart - flutter

class ExampleClass {
//default constructor
ExampleClass() {
//do stuff
}
//named constructor
ExampleClass.namedConstructor() {
//do stuff
}
}
void main() {
//is there a way to create a variable with datatype to store an object that is constructed only with a specific constructor?
//I have tried something like this, but it returns an error
ExampleClass.namedConstructor variable_1;
}
Is there any way to do this or an alternative? because I need to be able to differentiate between an object that is constructed with the default constructor or with a named constructor.

You can add some identification to classes builded with different constructors and compare entities by unique parameters.
If instances of your classes creating once (Singleton design pattern), you can create entities as constants and compare it by reference:
const administrator = User.administrator();
class User {
final int id;
User(this.id);
factory User.administrator() {
return User(0);
}
factory User.administrator(int id) {
return User(id);
}
}

Related

How to recreate singleton instance if different params are passed to the constructor in dart

I gathered the following understanding for creating a singleton in dart with params
class Foo extends ChangeNotifier {
late String channel;
void instanceMemberFunction () {
print('Foo created with channel $channel')
}
static final Foo _instance = Foo._internal();
Foo._internal() {
instanceMemberFunction();
}
factory Foo({
required String channel
}) {
_instance.channel = channel;
return _instance;
}
}
and I am calling the instance like so
Foo({channel: "bar"})
Now I want to have some working that if I use
Foo({channel: "baz"})
Then a new instance is created and it's okay in that case to destroy the old one. How can I achieve this in dart?
It seems like you've copied some existing example for creating a singleton without fully understanding what it's doing and why. The core parts are:
The single instance is stored in a global or static variable.
The class has one or more public factory constructors that returns that global/static variable, initializing it if necessary.
All other constructors for the class are private to force consumers to go through the factory constructors.
Therefore, if you want your factory constructor to replace its singleton based on its argument, you need to:
Make your factory constructor check if the argument is appropriate for the existing instance. If it is, return the existing instance. If not (or if there is no existing instance), create and return a new instance.
Since you need to check if the existing instance is initialized, make it nullable. (You alternatively could initialize it to a non-null sentinel value, e.g. Foo._internal(channel: '').
Pass the argument along to the private constructor.
class Foo extends ChangeNotifier {
final String channel;
void instanceMemberFunction () {
print('Foo created with channel $channel');
}
static Foo? _instance;
Foo._internal({required this.channel}) {
instanceMemberFunction();
}
factory Foo({required String channel}) {
if (channel != _instance?.channel) {
_instance = Foo._internal(channel: channel);
}
return _instance!;
}
}
Note that this implementation will create a new object if the constructor argument changes, which isn't very singleton-like. Depending on what you want to do, you could:
Return a new object (which could allow multiple simultaneous instances).
Return the existing object.
Return the existing object, but mutate it with the constructor argument.

How to set type definitions depending on the extending class in dartlang

Is there a way to declare return types of methods or the object-prefix to be the "extendingClass" like you would do in PHP with the static::class?
So for example:
abstract class AbstractModel {
// Should return the database-provider for the given model
dynamic get modelProvider;
// Save instance to Database - Create new if no ID exists,
// else update existing
dynamic save() {
if( id == null ) {
modelProvider.insert(this);
} else {
modelProvider.update(this);
}
return this;
}
}
class ToDo extends AbstractModel {
ToDoProvider get modelProvider {
return ToDoProvider;
}
}
So in this example, obviously AbstractModel does not yet know what the return type of modelProvider will be, but I do know that it will always be the same type for a given child. Also, the return type of the save method would always be the child-class. But when writing it like this I will get an error for overwriting the modelProvider with an invalid return type.
Due to darts javascript-like nature I assume there is no way to actually achieve this like you would in PHP. But then I wonder how to type-save build re-usable code? I am trying to implement a small eloquent like query-scheme for my models so I don't have to write each CRUD method for every model - but I would still like to be precise about the types and not use dynamic everywhere.
So is there a way to do that in dart or am I completely off the track regarding dart standards?
You can use generics:
abstract class AbstractModel<ChildType extends AbstractModel<ChildType>> {
// Should return the database-provider for the given model
ModelProvider<ChildType> get modelProvider;
// Save instance to Database - Create new if no ID exists,
// else update existing
ChildType save() {
if( id == null ) {
modelProvider.insert(this);
} else {
modelProvider.update(this);
}
return this;
}
}
class Model extends AbstractModel<Model> {
}
abstract class ModelProvider<T> {
void insert(T value);
void update(T value);
}
class MyModelProvider extends ModelProvider<Model> {
...
}

How to return multiple types of class types from single generic class in dart flutter?

I have multiple class like this:-
Class A {
static int xyz = 10;
int c;
int d;
static A getData() {
// Do something
return A()..c = xyz*5;
}
Class B {
static int abc = 10;
int c;
static B getData() {
// Do something
return B()..c = xyz*5;
}
So, here you can see that the the getData() is doing the same thing, but have different return types.
Is there any way to avoid duplicate implementation like this, can it be done by defining a single function which can reference the class and have multiple return type?
This has two parts: creating the object, and assigning to a field of the object.
Creating the object, you are mostly out of luck. The only way to create an object of a specific type in a generic method is by using reflection via dart:mirrors. However, you have indicated that this is for a Flutter project, and Flutter doesn't support reflection, so that isn't an option. The only way you are going to be able to dynamically create an object is to pass in a factory method that the generic method can call to construct the object.
Assigning to a field of the object is easier, but it requires that you either lose static type checking by using dynamic or by tying your classes together with inheritance. The latter is the preferable choice, but if you are working with a library than it isn't always an option.
Combining these two things, the code will look like this:
class Foo {
static int xyz = 10;
int c;
}
class A extends Foo {
int d;
static A getData() {
return modifyObject(() => A());
}
}
class B extends Foo {
static B getData() {
return modifyObject(() => B());
}
}
T modifyObject<T extends Foo>(T create()) {
return create()..c = Foo.xyz * 5;
}
Before doing this, though, I'd take a look at whether your project actually needs it. If your use case is as simple as your example, I would argue that this level of generalization is overkill and you are hurting your code's readability more than you are helping its modularity.

Typescript access static attribute of generic type

I have an abstract class Model with a static attribute and another generic class Controller<T extends Model>. I want to access the static attribute of Model in an instance of Controller. That should like this:
abstract class Model{
static hasStatus: boolean = false;
}
class MyModel extends Model{
static hasStatus = true;
}
class Controller<T extends Model>{
constructor(){
if(T.hasStatus)...
}
}
But TS says 'T' only refers to a type, but is being used as a value here.
Is there an easy way to achieve this? Or should i subclass Controller for each Heritage of Model and implement a method to retrieve the value?
There is no way to do that in typescript. Generic type parameters can only appear where types may appear in declarations, they are not accessible at runtime. The reason for that is simple - single javascript function is generated for each method of the generic class, and there is no way for that function to know which actual type was passed as generic type parameter.
If you need that information at runtime, you have to add a parameter to the constructor and pass a type yourself when calling it:
class Controller<T extends Model>{
constructor(cls: typeof Model){
if (cls.hasStatus) {
}
}
}
let c = new Controller<MyModel>(MyModel);
Here is how it looks when compiled to javascript to illustrate the point - there is nothing left of generic parameters there, and if you remove cls parameter there is no information about where hasStatus should come from.
var Controller = (function () {
function Controller(cls) {
if (cls.hasStatus) {
}
}
return Controller;
}());
var c = new Controller(MyModel);

Eclipse refactor overridden method into final and abstract parts

I have a method which i'd like to refactor
Basically i want to split the top level method in a abstract and a final part.
The method in question is overridden in quite a few places where additional functionality is added, but eventualy the super call is always made.
The code now basically look like:
(not all Extending classes override but those that do, do it this way)
class Base {
public Object getStuff(String key) {
out = //code to get data from the Database.
return out
}
class Extended1 extends Base {
public Object getStuff(String key) {
if("some_non_db_value".equals(key)) {
return "some custom stuff";
}
return super.getStuff(key);
}
}
What i'd like as a result would be something like:
class Base {
public final Object getStuff(String key) {
out = getCustom(key);
if(out != null) {
return custom;
}
out = //code to get data from the Database.
return out
}
public abstract Object getCustom(String key);
}
class Extended1 extends Base {
public Object getCustom(String key) {
if("some_non_db_value".equals(key)) {
return "some custom stuff";
}
return null;
}
}
I was hoping there would be a refactor action (or partial refactor) to get to (or closer to) this point.
I would first rename getStuff() to getCustom() which would take care of all the extended classes. Then changing the Base class should be relatively easy.