2

I have a Slide class with subclasses referring to the different types of slides (IntroSlide, SummarySlide, etc.):

abstract class Slide {
  String slideType;
  final String title;
  final String voiceover;
  final String? bgImage;
  final List<SlideContent> content;
}

class SlideContent { final String title; final String description; final String? image;

SlideContent({ required this.title, required this.description, this.image, }); }

// class IntroSlide extends Slide... // class SummarySlide extends Slide...

Some slides will not have bgImage or the image in SlideContent but those who do will have them as required.

Even though all subclasses have the same fields, each subclass will have its own view/presentation where the fields will be used in their own unique fashion.

If I want to automatically create a slide based on the slide type, how should I do it? I am fetching the json from an API endpoint. I can create a factory that maps all slide types to their respective subclass, but that would require me modifying the factory for each subclass I add. Does that follow OOP principles?

Hello
  • 47

3 Answers3

1

Having a factory method as the one-and-only place in the code that

maps all slide types to their respective subclass

is fine. It is a common approach in OO programming and often sufficient when the code sections where the new subclasses are defined are part of the same software product as the factory, and when they are under control of the same team which maintains the factory.

There are more complex solutions for the case when you need some kind of generic factory, maybe as part of some library, which does not have to be touched when a new subclass is created, but I would only recommend to use them when there are good reasons which justify their extra complexity.

Here are two approaches which come into my mind:

  • using reflection (so a generic component can identify at runtime which subclasses are available in a system and map them by some naming convention to some information from a text file)

  • using the prototype pattern (so objects of different subclasses can be registered as "examples" from different place in the code base, and the factory will only call their "Clone()" method to produce a specific object).

The prototype pattern, for example, allows you to implement a factory which creates just one object of each type, but does not know about the mapping - which keyword / constraints belong to which subclass. This is logic which can stay in the subclass itself this way. This can be combined with a reflection based factory, which creates the prototypes first.

Doc Brown
  • 218,378
1

I can create a factory that maps all slide types to their respective subclass but that would require me modifying the factory for each subclass I add. Does that follow OOP principles?

Such a factory doesn't follow the Open Closed Principle that says that a class should be open to extension but not modification. How much you should care that it doesn't depends on how expensive it is to redeploy this class that you're going to keep messing with. Today it's rarely as expensive as it used to be, say when a whole new chip would have to be burned and re-soldered into place on every unit. Today the cost is typically more that you have to re-test and re-peer-review the class.

So there is a draw back to creating such a factory. But there are times it's unavoidable.

Sometimes a class loader can be used to work around this problem. Then you can scan for classes. You can also use the abstract factory pattern to largely hide knowledge of construction. And you can build with what you know about today and let someone else build with the new stuff later. And you can just bite the bullet and modify an existing class.

The principles are not laws. They're warning signs that point to hidden costs. You have to decide what you want to pay.

If I want to automatically create a slide based off of the slide type, how should I do it?

This is actually a different question. You don't always need a factory that you pass enums or strings or such into. You can just do this:

  List<Slide> slides = [];
  slides.add(IntroSlide());
  slides.add(SummarySlide());

It's ok to call out what you want by name.

candied_orange
  • 119,268
0

Likely, what you are thinking about is having single method in the factory that contains a switch statement and takes a parameter (either a string or integer, maybe expressed as an enum) and returns a Slide object.

Other methods would then call the factory with the correct enum/int/string value to get a Slide object, and then either use the returned slide or pass the slide to some other object.

But here's a thought... Those other methods know exactly what slide sub-type they need, after all they have to understand which enum/int/string value maps to the correct slide sub-type. So instead of them calling this factory method to get the slide, have them create the correct slide sub-type directly.

With the above, you don't need the factory and you don't need to modify any function to add a new slide-subtype.

This is the OO way.


That said, if the int/string/enum value is coming from some configuration file, or other external source, then there is nothing in your code that knows what slide sub-type to use. In this case, you would need the factory function and you would need to modify it whenever adding a new slide sub-type. Some languages have a way of adding a new sub-type and updating the factory without having to modify any of its methods. I'm not sure if dart/flutter is one of them.

Daniel T.
  • 3,053