As a 3rd-party, I'm writing a program to interface with a webservice. The problem I've run into is that some classes end up being as commonly used as ints/strings (e.g. User), so I need to be careful with which responsibilities I give each class to prevent mega objects which depend on every other mega object.
The best example is the Group class (think Facebook group). A Group has an AuditLog (component) which contains LogItems. These LogItems specify target of an action, among other things such as time/etc. Sometimes the target of these logs is another Group, so the AuditLog needs to know how to create a new Group object from the data given by the webservice's response. This results in a circular dependency where Group needs to know how to create its component, AuditLog, and AuditLog needs to know how to create Groups.
So how would I resolve this? I could use dependency injection to pass an AuditLog object to the group upon creation, but this is detrimental to abstraction because the user has to know how the group object links together internally. This also becomes infeasible when there are many components that have to be added to the Group object this way. I could instead make a static class for AuditLog:
from group import Group from auditlog import AuditLog ourGroup = Group(ourGroupId) adLogs = AuditLog.getLogs(ourGroup, logType=Advertisement) groupsWeAdvertised = [log.target for log in adLogs if isinstance(log.target, Group)]
This is a lot better, but still doesn't seem ideal. AuditLog is a component of Group -- it is only used by Group, and it has no purpose without a Group, so breaking it off into a top-level class seems awkward. There's no way to easily know that this is a child object of group (it can't exist without Group) rather than some top-level service.
Is there a more ideal way to decouple this system? I looked over various Software Patterns and spent yesterday looking for similar problems on softwareengineering SE, but all solutions I found either involve breaking abstraction by requiring the user to manually initialize components of Group or decouple it entirely to where there's maybe not enough coupling to be healthy like in the example above.
Note: I am using Python, so even if circular dependency is somehow ideal, Python3 does not allow it.