Factory Design Patterns For Dart and Flutter
The Factory Method design, some of the time alluded to as the Virtual Constructor design, gives a method for covering an item’s creation rationale from client code, however, the item returned is ensured to stick to a known connection point. It’s one of the most broadly utilized creational designs since it adds a ton of adaptability to your article creation architecture without adding a lot of intricacies.
In this article, we’ll explore Factory Design Patterns For Dart and Flutter. We will perceive how to execute a demo program. Classic Factory Method model appearance how to deftly deliver objects addressing different shapes, then we’ll investigate how you can involve the example to make UI components for various stages in Flutter without any problem.
Table Of Contents ::
Using Factory Method In Flutter
The Abstract Factory Method Pattern
Classic Factory Method Model:
Let’s begin with an excessively shortsighted, yet exemplary, model that will assist with making the Factory Method example’s structure understood. We’ll make a shape factory that supports creating a circle or a square shape. The accompanying chart outlines the essential components and connections:
The Shape class will go about as the factory and the connection point for the model, while Circle and Square are instances of substantial results of the production factory. The items execute the implement factory’s point of interaction, giving substantial executions of the draw() strategy.
How about we find out what it resembles as Dart code:
enum ShapeType {
circle,
square
}
abstract class Shape {
factory Shape(ShapeType type) {
switch (type) {
case ShapeType.circle: return Circle();
case ShapeType.square: return Square();
default: return null;
}
}
void draw();
}
class Circle implements Shape {
@override
void draw() {
print("Circle");
}
}
class Square implements Shape {
@override
void draw() {
print("Square");
}
}
Next comes the item factory, which for this situation appears as an abstract class called Shape. The shape has a factory constructor that goes about as the factory strategy for this example. It’s liable for making shapes of the mentioned type. The class is marked abstract
conceptual to deny direct launch of Shape since the class has no execution for the draw() technique.
A switch proclamation is used to return the fitting substantial shape, returning null on the off chance that an invalid kind is passed in. The class closes with an unimplemented statement of a draw() strategy, present just to lay out a point of interaction that all shapes should execute.
The Circle and Square classes each carry out the Shape interface by superseding the draw() technique, as demonstrated by the @override
metatag, which is discretionary but suggested as a type of self-documentation. The production line strategy in the Shape class can’t return a class that neglects to execute this connection point accurately.
Utilizing the factory could look something like the accompanying:
final shape1 = Shape(ShapeType.circle);
final shape2 = Shape(ShapeType.square);
shape1.draw();
shape2.draw();
Through the enchantment of polymorphism, the right adaptation of draw() for each shape will be called. Both shape1 and shape2 are of type Shape, however, one is a circle and the other is a square. It would be feasible to make a List<Shape> containing a blend of shape types, and the draw() strategy could be required each without the guest having to know every component’s actual kind.
Using Factory Method In Flutter:
One clear use for the Factory Method design in a Flutter application would produce locally styled UI components for various stages. For this model, we’ll make a platform-aware button factory that will return buttons for Android or iOS:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
abstract class PlatformButton {
factory PlatformButton(TargetPlatform platform) {
switch (platform) {
case TargetPlatform.android: return ShowAndroidButton();
case TargetPlatform.iOS: return ShowIosButton();
default: return null;
}
}
Widget build({
@required BuildContext context,
@required Widget child,
@required VoidCallback onPressed
});
}
As in the shapes model from the earlier segment, we make an abstract class to house the production line strategy. The industrial facility constructor of PlatformButton will return a case of a class that executes PlatformButton in light of the worth of its platform
parameter.
The switch proclamation accomplishes crafted by returning a button example that matches the caller’s inclination. Note that ShowAndroidButton and ShowIosButton haven’t yet been made.
PlatformButton likewise incorporates an unimplemented statement for a build()
strategy to lay out an assumption that practitioners will supersede it with a viable mark. The build()
strategy takes the boundaries expected by the stage explicit button widgets.
Here are the implementations for ShowAndroidButton and ShowIosButton:
class
ShowAndroidButtonimplements PlatformButton {
ShowIosButton
@override
Widget build({
@required BuildContext context,
@required Widget child,
@required VoidCallback onPressed
}) {
return FlatButton(
child: child,
onPressed: onPressed,
);
}
}
classimplements PlatformButton {
@override
Widget build({
@required BuildContext context,
@required Widget child,
@required VoidCallback onPressed
}) {
return CupertinoButton(
child: child,
onPressed: onPressed,
);
}
}
ShowAndroidButton and ShowIosButton carry out the connection point laid out by PlatformButton, and each class build()
technique returns a button widget styled by those separate platforms. The child and onPressed arguments are given to those widgets.
Some place in the application, a PlatformButton factory line can be made this way:
PlatformButton(TargetPlatform.android)
Or on the other hand more probable, the stage would be distinguished powerfully by utilizing a Flutter Theme:
PlatformButton(Theme.of(context).platform)
Along these lines, every one of the buttons for an application could be consequently delivered in the style of the host stage, and the application’s build methods won’t be jumbled up by excess stage identification code.
What’s more, to build a button, you’ll have to call the build()
strategy:
PlatformButton(Theme.of(context).platform).build(
context: context,
child: Text('My Button'),
onPressed: () => print('Button pressed!'),
)
With just somewhat more code than a typical button launch, you can have a button utilizing Android’s Material Design style or one that utilizes the iOS look and feel, given the stage your Flutter application is executing on.
The Abstract Factory Method Pattern:
The Abstract Factory Method design is a superset of the Factory Method design. All things considered, a focal production line class handles those subtleties imperceptibly. The client need just give the sort of object required, and the abstract industrial factory figures out which object factory to start up, then it returns the proper item.
This extended model will uphold the production of various stage explicit UI widgets, so we’ll utilize the PlatformButton, ShowAndroidButton, and ShowIosButton classes from the Factory Method design model, and we’ll add equivalent help for switch widgets:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
abstract class PlatformSwitch {
factory PlatformSwitch(TargetPlatform platform) {
switch (platform) {
case TargetPlatform.android: return ShowAndroidSwitch();
case TargetPlatform.iOS: return ShowIosSwitch();
default: return null;
}
}
Widget build({
@required BuildContext context,
@required value,
@required ValueChanged<bool> onChanged
});
}
This code scrap will look recognizable to you if you’ve investigated the button creation code from the Factory Method design model. PlatformSwitch performs indistinguishably from PlatformButton, yet with switches.
Then, we really want classes for the two unique switches we’ll uphold. These are practically equivalent to their button partners from the Factory Method design model, with a couple of parameters adjusted:
class ShowAndroidSwitch implements PlatformSwitch {
@override
Widget build({
@required BuildContext context,
@required value,
@required ValueChanged<bool> onChanged
}) {
PlatformButton(Theme.of(context).platform);
return Switch(
value: value,
onChanged: onChanged,
);
}
}
class ShowIosSwitch implements PlatformSwitch {
@override
Widget build({
@required BuildContext context,
@required value,
@required ValueChanged<bool> onChanged
}) {
return CupertinoSwitch(
value: value,
onChanged: onChanged,
);
}
}
Since we have factories for two UI controls set up, we can build an abstract factory class to deal with making the right version of every widget from a central widget factory:
class WidgetFactory {
static Widget buildButton({
@required BuildContext context,
@required Widget child,
@required VoidCallback onPressed
}) {
return PlatformButton(Theme.of(context).platform).build(
context: context,
child: child,
onPressed: onPressed,
);
}
static Widget buildSwitch({
@required BuildContext context,
@required value,
@required ValueChanged<bool> onChanged
}) {
return PlatformSwitch(Theme.of(context).platform).build(
context: context,
value: value,
onChanged: onChanged,
);
}
}
We make all the WidgetFactory strategies static to stay away from the need to start up it. With it, you can fabricate a button or a switch widget, and for each situation, you’ll get the rendition compared to the stage your application is running on. Luckily, WidgetFactory can decide the stage utilizing the BuildContext, so the client code doesn’t need to give it a different boundary.
The buildButton() technique utilizes the button production line class, PlatformButton, to make either an Android or iOS button, then, at that point, sends that button back to the caller. The buildSwitch() technique does likewise for switches. More techniques can be added to help with different controls.
To utilize the WidgetFactory, simply call one of the build techniques:
WidgetFactory.buildSwitch(
context: context,
value: myValue,
onChanged: (bool value) => print(value),
)
As may be obvious, the Abstract Factory Method design enjoys a couple of upper hands over the Factory Method design. There’s somewhat more standard included, however, the client code is more limited and doesn’t have to expressly pass the stage identifier, since that can be recognized through the context
.
Conclusion:
In the article, I have explained the basic structure of Factory Design Patterns For Dart and Flutter; you can modify this code according to your choice. This was a small introduction to Factory Design Patterns For Dart and Flutter On User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on Trying up the Factory Design Patterns For Dart and Flutter in your projects. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Clap 👏 If this article helps you.
Feel free to connect with us:
And read more articles from FlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.