Looking through the class that defines BlocObserver, all the methods do not have any functionality defined. The BlocObserver does not inherit anything from any other class. It is only connected to the Bloc class by being created during instantiation of a Bloc.
How do the methods in BlocObserver have functionality when they are empty inside BlocObserver?
Read through the BlocObserver definition, and read through the Bloc definition.
What to do
The way you are expected to use BlocObserver is described pretty well in Core Concepts.
Basically, as BlocObserver is an abstract class, you would extend it in your own class, providing implementations for the handler methods as appropriate for your use-case.
So, roughly:
class CustomObserver extends BlocObserver {
#override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
// Perform logic based on the change
}
}
Then, you would assign an instance of this class as the static observer on Bloc, for example:
Bloc.observer = CustomObserver();
After this point, you would expect any changes that propagate through Bloc to call your CustomObserver.onChange() method.
How this works
The pattern of providing some framework object a definition of the code you'd like to run when certain events happen is a pretty common one, so it's useful to come to grips with it. Usually (and also in this case) it's way simpler than it appears.
As discussed above, you provide a BlocObserver to Bloc by setting a static member. This means both that:
you can only have one observer in the system at a time, and
any code can access it directly by calling Bloc.observer
Then, when making state changes, you ensure you do so via an instance of BlocBase (such as Cubit), which takes care of calling the appropriate method on our observer.
So, once again using Core Concepts as a base, when calling CounterCubit().increment(), the call stack looks like this:
CounterCubit.increment
CounterCubit.emit/Cubit.emit/BlocBase.emit (through inheritance)
CounterCubit.onChange
BlocBase.onChange
SimpleBlocObserver.onChange
At this point, you're back in your own code, and you can see that SimpleBlocObserver.onChange(...) calls super.onChange(...). No magic, just function calls.
Related
Here is my architecture, I have two statfull widgets: ProfilePicture, RoundedProfilePicture. ProfilePicture is a statefull widget and it has complicated custom code which is very prone to error so I dont want to copy paste it, it utilizes variables from Picture abstract class. (ie. fetches server data and stores them inside variables of Picture). What I want to do is I want to extend from this widgets state so that I can create a new widget RoundedProfilePicture. This widgets state will basically utilize the complicated code from ProfilePicture's state with inheritance and it will add small extra logic to it. So I thought inheritance is the best choice here. Here is what I tried so far
class ProfilePictureState extends State<ProfilePicture> implements Picture{
// SOME LONG COMPLICATED 500 LINE OF CODE
}
class RoundedProfilePictureState extends ProfilePictureState {
#override
void initState() {
super.initState(); // this calls ProfilePictureState.initState() call. I want to call State<ProfilePicture>.initState()
}
}
My problem is void initState() in RoundedProfilePictureState requires me to make a super.initState() call. This call makes a ProfilePictureState.initState() call. I want to call State<ProfilePicture>.initState() because I want to add a different logic in my init state call. So the structure is:
----abstract State class
---ProfilePictureState
--RoundedProfilePictureState
How can I make a call to abstract State class's initState method from RoundedProfilePictureState? Is this possible?
Since no one answered, here is how I solved this. I think this is impossible to achieve. What I did is I moved the code and all the variables to a mixin. Took like an hour or two to do so. I achieved my needs tho.
I'm teaching myself Flutter, having previously studied traditional object oriented languages. I'm still a beginner, but it's clear state management is a key issue in Flutter, so I'm learning about it (mostly with Providers).
Much of what I'm learning seems like using global variables, set and called from other classes (with notifyListener() calls in the latter case). But when I learned about OOP I was taught this was a "bad" thing. One object may inadvertently change a variable's value, breaking another object. In other words, encapsulation is good, global variables are bad--they violate the encapsulation idea.
What am I missing?
The provider model (or more generally, the subscriber-listener model) does not break encapsulation. For encapsulation to be broken, changes in one object directly result in the mutation of another object. For example, if you had these two classes:
class A {
int x;
B b;
}
class B {
String s;
A a;
}
So here we have a co-dependency between A and B. Now say there was a method in A to mutate its state:
void changeState(int i) {
this.x = i;
b.s = i.toString();
}
This breaks encapsulation because A is directly changing the state of B, which could result in some broken functionality as B attempts to operate with an externally mutated state.
Now say that there is no explicitly defined co-dependency, and A and B instead communicate through an event bus:
// A
void changeState(int i) {
this.x = i;
fireEvent('A-changed', this);
}
// B
listenToEvent<A>('A-changed', handleEvent);
...
void handleEvent(A source) {
this.s = source.x.toString();
}
Now encapsulation is maintained because A and B are communicating their state changes, and each one is responsible only for maintaining its own state.
This is exactly what happens in provider with ChangeNotifier. When an object updates its state and then calls notifyListeners, Flutter uses an internal event bus to notify any widget that is listening to that object, either explicitly or via provider's Provider.of or use of a Consumer. The object is not directly causing the widget to rebuild, but is instead communicating through the event bus and informing the widget that it should rebuild itself. This preserves encapsulation as every object involved is only ever responsible for its own state.
As for how provider is different from global variables, that's because provider utilizes a pattern called "dependency injection" (or DI for short). With DI, you can take a non-global object and "inject" it into the widgets that "depend" on it. This is most commonly done through a constructor, i.e.:
class SomeService {
Database db;
SomeService(this.db);
}
In that example, the SomeService class needs to communicate with a database, but instead of calling some global database service, it has the Database object passed to it upon its creation. This gives SomeService a database to communicate with without relying on a global object. (This also allows you to mock the Database object for testing purposes.)
With provider, it implements DI using a slightly different approach. Instead of using constructors, provider embeds the resources into the widget tree. Widgets from that point in the tree down will then be able to retrieve that resource dynamically, but widgets that are above that point or in a different section of the tree will not have access to it. This is how provider implements DI, and is what separates it from global variables.
From the docs I understood that one can call addListener() on a ChangeNotifier instance to add a custom listener to the stack.
This method accepts a callback with zero arguments (according to notifyListeners()), e.g.:
class MyClass extends ChangeNotifier {
MyClass() {
addListener(() {
// ...
});
}
}
From within the callback, how does one find out what properties or parts of MyClass have been changed?
ChangeNotifier does not have such capabilities inherently. You will have to implement your own logic. Specifically, you either have access to all of the properties of your ChangeNotifier implementation because you add the listener in its scope or you have access to it because you have a reference to it in your scope.
ChangeNotifier simply implements Listenable and provides some utilities for managing listeners. Furthermore, the documentation states the following about it:
ChangeNotifier is optimized for small numbers (one or two) of listeners. It is O(N) for adding and removing listeners and O(N²) for dispatching notifications (where N is the number of listeners).
I am not sure about options with better runtime complexity for notifying listeners, but you will not run into any issues in a regular Flutter app.
ValueNotifier
ValueNotifier is a pre-made implementation of ChangeNotifier that will notify its listeners when its value property is changed.
This is sufficient for most case, but since it appears that you want to create a custom ChangeNotifier, you can use the source code of ValueNotifier to take a look at an example implementation (it is very straight forward).
If you are just looking to do state management in general, ValueNotifiers usually work great. However, they are not applicable in every scenario. Hence, here is an extensive list with different state management options.
Considering the questions, I think the techniques that fit your needs best and the most popular options are the following:
InheritedWidget as it lets you notify dependents based on what data changed. Additionally, there is InheritedModel as an extension of this and InheritedNotifier that works with Listenable, just like ChangeNotifier does.
The BLOC pattern, which works with streams.
The provider package which is mostly a convenience wrapper for various Flutter state management techniques (InheritedWidget, StatefulWidget, ValueNotifier, etc.).
I've been reading up a bit about coffeescript's inheritance model and I have the feeling I'm on the fringes of an ideological debate which I really don't understand. So, I would be perfectly happy to find out that I'm just doing things in the wrong way.
Basically what I am doing is writing a set of widgets which, among other things, need to handle events on their DOM elements. I thought a good way to go about this would be to have a class method which would be called once, to delegate all the events which the widget might need. The base widget class might have some simple click handlers, while the subclass might add to that some mouseover handlers or extra click handlers.
However, it appears that I'm not supposed to try and do the equivalent of calling super() inside a static method. There is a workaround which exists, (this.__super__.constructor.METHODNAME() but I've seen a lot of suggestions that this isn't the best way to do what I'm trying to do. Has anyone got any insights on how I should structure this code? Keep using the workaround, or put all the delegation into a totally different place? I can't really just stick it in the prototype, since I won't necessarily have an instance to call the method on (or can I essentially still call a method on the prototype from a static context, like putting SwatchableWidget.prototype.delegateEvents() into an onload function or something?
Here's a bit of code to illustrate what I'm talking about:
class Widget
#testProp: "ThemeWidget"
#delegateEvents: ->
console.log "delegate some generic events"
class SwatchableWidget extends Widget
#testProp2 = "SwatchWidget"
#delegateEvents: ->
console.log "delegate some specific swatchable widget events"
this.__super__.constructor.delegateEvents()
Widget.delegateEvents()
SwatchableWidget.delegateEvents()
Thanks for any help.
I suggest replacing
this.__super__.constructor.delegateEvents()
with
Widget.delegateEvents()
trying to use super to call static methods is not required (and doesn't make much sense)
I don't understand why delegateEvents would be a class-level method, or why Widget.delegateEvents have to be called again from SwatchableWidget.delegateEvents. If it's just class initialization code, you should put it in the class body directly:
class Widget
console.log "delegate some generic events"
...
#testProp: "ThemeWidget"
class SwatchableWidget extends Widget
console.log "delegate some specific swatchable widget events"
...
#testProp2 = "SwatchWidget"
I take it you're waiting for a specific DOM state before running this initialization code? Maybe I could suggest another approach if you told me a little bit more about the preconditions for delegateEvents.
It sounds like you want a different type of inheritance model where each inherited function of a certain type ("parent calling") will walk the inheritance tree and call all its parents with the same name.
You could call any direct parent functions in each child manually as you've written. Then it will float up the inheritance chain anywhere you specify such a relationship.
I would bind the parents delegate call in the constructor to a current class function
delegateparents =>
#call any parent class methods
I have a question, and I'm going to tag this subjective since that's what I think it evolves into, more of a discussion. I'm hoping for some good ideas or some thought-provokers. I apologize for the long-winded question but you need to know the context.
The question is basically:
How do you deal with concrete types in relation to IoC containers? Specifically, who is responsible for disposing them, if they require disposal, and how does that knowledge get propagated out to the calling code?
Do you require them to be IDisposable? If not, is that code future-proof, or is the rule that you cannot use disposable objects? If you enforce IDisposable-requirements on interfaces and concrete types to be future-proof, whose responsibility is objects injected as part of constructor calls?
Edit: I accepted the answer by #Chris Ballard since it's the closest one to the approach we ended up with.
Basically, we always return a type that looks like this:
public interface IService<T> : IDisposable
where T: class
{
T Instance { get; }
Boolean Success { get; }
String FailureMessage { get; } // in case Success=false
}
We then return an object implementing this interface back from both .Resolve and .TryResolve, so that what we get in the calling code is always the same type.
Now, the object implementing this interface, IService<T> is IDisposable, and should always be disposed of. It's not up to the programmer that resolves a service to decide whether the IService<T> object should be disposed or not.
However, and this is the crucial part, whether the service instance should be disposed or not, that knowledge is baked into the object implementing IService<T>, so if it's a factory-scoped service (ie. each call to Resolve ends up with a new service instance), then the service instance will be disposed when the IService<T> object is disposed.
This also made it possible to support other special scopes, like pooling. We can now say that we want minimum 2 service instances, maximum 15, and typically 5, which means that each call to .Resolve will either retrieve a service instance from a pool of available objects, or construct a new one. And then, when the IService<T> object that holds the pooled service is disposed of, the service instance is released back into its pool.
Sure, this made all code look like this:
using (var service = ServiceContainer.Global.Resolve<ISomeService>())
{
service.Instance.DoSomething();
}
but it's a clean approach, and it has the same syntax regardless of the type of service or concrete object in use, so we chose that as an acceptable solution.
Original question follows, for posterity
Long-winded question comes here:
We have a IoC container that we use, and recently we discovered what amounts to a problem.
In non-IoC code, when we wanted to use, say, a file, we used a class like this:
using (Stream stream = new FileStream(...))
{
...
}
There was no question as to whether this class was something that held a limited resource or not, since we knew that files had to be closed, and the class itself implemented IDisposable. The rule is simply that every class we construct an object of, that implements IDisposable, has to be disposed of. No questions asked. It's not up to the user of this class to decide if calling Dispose is optional or not.
Ok, so on to the first step towards the IoC container. Let's assume we don't want the code to talk directly to the file, but instead go through one layer of indirection. Let's call this class a BinaryDataProvider for this example. Internally, the class is using a stream, which is still a disposable object, so the above code would be changed to:
using (BinaryDataProvider provider = new BinaryDataProvider(...))
{
...
}
This doesn't change much. The knowledge that the class implements IDisposable is still here, no questions asked, we need to call Dispose.
But, let's assume that we have classes that provide data that right now doesn't use any such limited resources.
The above code could then be written as:
BinaryDataProvider provider = new BinaryDataProvider();
...
OK, so far so good, but here comes the meat of the question. Let's assume we want to use an IoC container to inject this provider instead of depending on a specific concrete type.
The code would then be:
IBinaryDataProvider provider =
ServiceContainer.Global.Resolve<IBinaryDataProvider>();
...
Note that I assume there is an independent interface available that we can access the object through.
With the above change, what if we later on want to use an object that really should be disposed of? None of the existing code that resolves that interface is written to dispose of the object, so what now?
The way we see it, we have to pick one solution:
Implement runtime checking that checks that if a concrete type that is being registered implements IDisposable, require that the interface it is exposed through also implements IDisposable. This is not a good solution
Enfore a constraint on the interfaces being used, they must always inherit from IDisposable, in order to be future-proof
Enforce runtime that no concrete types can be IDisposable, since this is specifically not handled by the code using the IoC container
Just leave it up to the programmer to check if the object implements IDisposable and "do the right thing"?
Are there others?
Also, what about injecting objects in constructors? Our container, and some of the other containers we've looked into, is capable of injecting a fresh object into a parameter to a constructor of a concrete type. For instance, if our BinaryDataProvider need an object that implements the ILogging interface, if we enforce IDispose-"ability" on these objects, whose responsibility is it to dispose of the logging object?
What do you think? I want opinions, good and bad.
One option might be to go with a factory pattern, so that the objects created directly by the IoC container never need to be disposed themselves, eg
IBinaryDataProviderFactory factory =
ServiceContainer.Global.Resolve<IBinaryDataProviderFactory>();
using(IBinaryDataProvider provider = factory.CreateProvider())
{
...
}
Downside is added complexity, but it does mean that the container never creates anything which the developer is supposed to dispose of - it is always explicit code which does this.
If you really want to make it obvious, the factory method could be named something like CreateDisposableProvider().
(Disclaimer: I'm answering this based on java stuff. Although I program C# I haven't proxied anything in C# but I know it's possible. Sorry about the java terminology)
You could let the IoC framework inspect the object being constructed to see if it supports
IDisposable. If not, you could use a dynamic proxy to wrap the actual object that the IoC framework provides to the client code. This dynamic proxy could implement IDisposable, so that you'd always deliver a IDisposable to the client. As long as you're working with interfaces that should be fairly simple ?
Then you'd just have the problem of communicating to the developer when the object is an IDisposable. I'm not really sure how this'd be done in a nice manner.
You actually came up with a very dirty solution: your IService contract violates the SRP, wich is a big no-no.
What I recommend is to distinguish so-called "singleton" services from so-called "prototype" services. Lifetime of "singleton" ones is managed by the container, which may query at runtime whether a particular instance implements IDisposable and invoke Dispose() on shutdown if so.
Managing prototypes, on the other hand, is totally the responsibility of the calling code.