When to use Factory in abstract classes?

Asked

Viewed 197 times

4

Abstract classes are classes that cannot be instantiated and their implementation depends on other classes, but using the keyword Factory can "instantiate" an abstract class.

So, how and when to use this resource?

  • Factory Logger(String name) { Return _cache.putIfAbsent( name, () => Logger._Internal(name); }

2 answers

3


You know that the abstract class cannot be instantiated, but it can have a constructor as long as it constructs an object of a concrete class, and of course, the correct thing is that this object is of a class derived from that abstract.

So you can use the abstract class as a way of deciding what to do. You can have a default class that is created in most cases or you can have a choice based on some parameter or some information that can be taken globally.

Note that if the constructor were normal it would have to generate a concrete object derived from it, this is what constructors do, but it would have to return the type of the abstract class, which is not what is desired. The mechanism allows returning the concrete type.

It is useful when application code does not need to know which child classes to use. So you who are doing the application just need to know the general class and it turns around to give you the best possible object for the situation, probably according to configuration you gave (which in the background ends up exposing minimum knowledge of what exists). Thus the child classes become details of implementation. And indeed the abstract class needs to have knowledge of which daughter classes exist, even if indirectly.

It’s interesting, but I think using inheritance for that is wrong in most situations. Since the class must know the daughters and these are very similar to the mother class, then why not only make the mother class more flexible to have different behaviors according to some parameter in its own constructor?

Remembering that every raised daughter will make her mother change.

I think the main reason this mechanism was created is precisely what is in the commentary, it’s even example of documentation, and return an instance of the class itself with a logic a little more complex than a normal constructor could.

The example of documentation is a good use, already with abstract class, but me, it is abuse. You can use it, but it usually has a simpler way of doing it and it’s wanting to make object orientation be used where it has zero benefit (note that I didn’t say little).

Obviously it can have some exception and find a really valid scenario, but probably it would be something involving reflection, it is a lot of complication for still a small gain and still force the application to know some implementation detail, even if not all of it.

Another good example is to create a Singleton.

The reason for using is up there in the answer, but I would consider that you should not use in this case. If using would be something like this:

abstract class WidgetService {
    WidgetService _cached; 
    factory WidgetService(String type) {
        switch (type) {
            case 'a': return new ConcreteWidgetServiceA();
            case 'b': return new ConcreteWidgetServiceB();
            default: throw new ArgumentError("precisa de um nome válido");
        }
    }
    Widget getWidget();
    void saveWidget(Widget widget);
}

class ConcreteWidgetServiceA extends BaseWidgetService implements WidgetService {
    WidgetService();
    Widget getWidget() {
        // code to get widget here
    }
    void saveWidget(Widget widget) {
        // code to save widget here
    }
}

class ConcreteWidgetServiceB extends BaseWidgetService implements WidgetService {
    WidgetService();
    Widget getWidget() {
        // code to get widget here
    }
    void saveWidget(Widget widget) {
        // code to save widget here
    }
}

I put in the Github for future reference.

Source.

This way you only need to know the class WidgetService and what parameter to pass to it. This seems very wrong and unnecessary because you can create a normal static method that does the factory and deal with it if you really need the dynamism imposed by that standard, and again, it indicates that you shouldn’t have an inheritance since any new daughter would have to change the mother class.

Reinforcement, for everything has exception, but a mechanism in the language should not deal with rare cases but with cases that happen a lot. Of course having the mechanism will create a tendency to write code like this and it will not be so rare, do something bad.

2

Abstract classes are classes that cannot be instantiated

Correct. What characterizes it by definition of Dart Language tour is the fact that it cannot be instantiated.

and its implementation depends on other classes,

Not completely. It may be that only a few methods are abstract as well. It is not necessary that all are. This class can also have properties (attributes) without any problems. A sub-class of this abstract class only needs to provide the implementation of abstract methods.

but using the key word Factory one can "instantiate" an abstract class.

Kind of. It will appear, for the purpose of the code, to have been instantiated, but its main use is for you to have greater control over its creation. That is, for example, you can return an instance of a specific subclass always (you can apply the pattern of Singleton). You can, depending on the parameter you passed to factory constructor, choose the appropriate subclass to be instantiated.

Then how and when to use this resource?

When it makes sense to you. If you need to create a Singleton, or if you need to do a procedure to find out which sub-class needs to be instantiated are good examples. Syntactically there is nothing but simply applying both concepts simultaneously:

abstract class numero {
 List<int> numerosEscolhidos = [];

  String nomePorExtensoDoNumero();  // Método abstrato.

  factory numero(double numero) {
      numerosEscolhidos.insert(numero);
      if (numero%2==0)
         return classePar(numero);
      return classeImpar(numero);
    }


}
  • 1

    Your second statement doesn’t seem to make sense or is wrong.

  • I edited for better understanding as suggested. Thank you :)

  • Dependency continues to exist at all times.

  • 1

    What would be the dependency specifically? For I cannot see

  • The "dependence" he referred to was relative to the word depends on in your question, in the phrase: "and its implementation depends on other classes". In my reply, I make it clear that although this dependency always exists, it is not obligatory that the entire implementation be contained in other classes. The abstract class may contain some implementation of its own as described here (Abstract classes are Useful for Defining interfaces, often with some implementation.)

  • No, your answer first said it never depends, now it says it sometimes doesn’t, so it doesn’t make it clear that dependency always exists. In fact apart from that which is wrong the rest does not mean anything to it, it has not been asked if some methods have implementation and others not, it ended up generating confusion.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.