5

I have the following architecture:

         +-----------------+
         |   Collection    |
         |                 |
         |                 |
         |                 |
         |                 |
         +-----------------+
           |        ^
           |        |
  Create() |        |
           |        |
           v        | GetItem(B)
+------------+      |
|   Item A   |      |
|            |      |
|            +------+
|            |
+------------+

A class managing a collection of items, creates items. And these items may need other items from the collection.

The actual code is in python, and for now the Collection passes itself as a parameter to the created Item. As I see it, it is a bad practice. The only improvement I can see it to pass the few functions of Collection needed by the Item, instead of the whole instance.

For example:

class Collection:
    GetItem(self, id):
        ...
    CreateItem(self, id):
        item = Item(id, self) # <-- pass self
        ...

class Item:
    __init__(self, id, col):
        ...
        col.GetItem(...)

How can I avoid passing self as parameter? Or is it a common usage in Python?

More detailed example

 ┌──────┐            ┌──────────┐           ┌─────┐                              
 │Client│            │Collection│           │ItemA│                              
 └──┬───┘            └────┬─────┘           └──┬──┘                              
    │ UpdateItem(A, param)│                    │                                 
    │ ────────────────────>                    │                                 
    │                     │                    │                                 
    │                     │ Update(param, self)│  ╔═════════════════════════════╗
    │                     │ ───────────────────>  ║Need to update linked ItemB ░║
    │                     │                    │  ╚═════════════════════════════╝
    │                     │     GetItem(B)     │                                 
    │                     │ <───────────────────                                 
    │                     │                    │                                 
    │                     │        ItemB       │                                 
    │                     │  ─ ─ ─ ─ ─ ─ ─ ─ ─ >                                 
    │                     │                    │                                 
    │                     │                    │────┐                            
    │                     │                    │    │ UpdateItemB()              
    │                     │                    │<───┘                            
 ┌──┴───┐            ┌────┴─────┐           ┌──┴──┐                              
 │Client│            │Collection│           │ItemA│                              
 └──────┘            └──────────┘           └─────┘                              
user4780495
  • 2,642
  • 2
  • 18
  • 24
  • Check the MutableSequence class from the collections module. – Ignacio Vergara Kausel Jul 25 '17 at 12:28
  • I believe that an actual example would help find the pattern that would best fit to your need. – Ori Jul 25 '17 at 13:25
  • Example added. Hope this helps. – user4780495 Jul 25 '17 at 13:32
  • Btw: nicely written question! How did you create the "ascii art" for those sequence diagrams? – GhostCat Jul 25 '17 at 14:18
  • 1
    Thanks. [Plantext](https://www.planttext.com/) for the sequence diagram. (help for the syntax [here](http://plantuml.com/sequence-diagram) - plantuml is a nice tool for UML). And [asciiflow](http://asciiflow.com/) for the simple box diagram. – user4780495 Jul 25 '17 at 14:29
  • What service is Collection supposed to be providing to Client (the example shows updates, but is there more?). It seems like a Façade to simplify the access to the aggregates and to prevent direct coupling. Why not consider how collections are handled in other libraries? There are lots of patterns, including Iterator and Factory method. – Fuhrmanator Jul 26 '17 at 21:34
  • The Collection (Facade) uses a Factory when the client needs to create an Items. Then the Item is stored in a DB. When the client wants to update an Item, the Facade instanciate the Item from the data stored in DB and then updates it (the Factory is not used here, for the update). The Collection is in charge of all the operation on multiple Items (querry a given type of Item, count some properties, etc.). – user4780495 Jul 27 '17 at 06:17

2 Answers2

1

A non-answer: given the current level of detail, recommending a specific pattern is the wrong approach! Coming from the DDD perspective, I am wondering if you should rather step back and should look at your model at a whole.

It looks like your are mixing up at least two responsibilities within your "collection" class:

  • knowledge to create objects
  • and to update them

DDD suggests to have factories that are responsible for creating objects.

And instead of thinking of a collection that provides access to all kinds of entries, you might rather define aggregates, and identify their root objects. Because you want to make sure that there is only one defined "path" to get to certain information.

In other words: you should strive to design a model that provides helpful abstractions for the real world elements you are dealing with. And your current implementation feels like it is something that evolved out of some technical ideas how to organize things. Thus the recommendation: step back and look at big picture.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
0

Seems like a classic place to user the composite pattern: https://sourcemaking.com/design_patterns/composite

Each instance can be a collection or an item and your client can use them interchangeably.

Jonathan Oron
  • 34
  • 1
  • 7
  • Actually, the `Collection` class is a "Facade". The client request basic operations on the items via the `Collection`. And the `Collection` and the `Item`s manage the dependencies and other stuff. – user4780495 Jul 25 '17 at 12:53
  • True, but it can be a composite which *has a* facade and not *is a* facade. – Jonathan Oron Jul 26 '17 at 06:18