Skip to content

DI: Container - register by interface #20

@jakos

Description

@jakos

We had a conversation about the difference between registering by name and registering by interface. I passed some motivations, stating that:

  • when you place a interface into inject object (ie. use annotation), both your IDE and static code analyzer know what fields & methods it has (great!),
  • there are times when you don't have possibility to provide an interface that all implementations inherit from (with factory methods in particular); then you can use registering by name,

And now I have the ultimate reason to differ between interface & name registration. Consider following example (exaggerated a bit, but only a tiny):

class ISession:

    @property
    def id(self): ...
    def save_data(self, key, data): ...
    def get_data(self, key): ...

class RedisSession:
    ...  # implementation

class ISessionWithUser(ISession):
    user: entities.User

class UserRedisSession(ISessionWithUser):
    ...  # implementation

# registering sub-interface
container.register_by_interface(ISessionWithUser, UserRedisSession)
# ... allows finding them with their parent interface
container.find_by_interface(ISession)
# >>> returns UserRedisSession instance even though its registration
# interface was more specific than the one given at the lookup call

Three notes:

  • do you want to implement this use case in this issue or is it enough for you?
  • here I see some benefit using a decorator to indicate that something is an interface for something: you do not have to look every time in the runtime iff queried interface has some subclass which provides a constructor
  • we already have an util to find all subclasses of a class (pca.utils.inspect.get_all_subclasses), so it isn't too hard to implement
  • if getting all sub-interfaces sounds time-consuming, you could use registration time (ie. application startup time; as then exist all super-interfaces of registered interface).

Eventually, described feature is just an application of Liskov Substitution Principle to our Dependency Injection solution.

Tell me what do you think about this.

Originally posted by @lhaze in #19 (comment)

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions