johhny B
johhny B

Reputation: 1452

Composition OOP

I have a class A that contains Class B in a strict sense of a 'has-a' relationship I.e. It makes sense for A to contain B. However there are only a couple of specific methods calls on B will affect A. For the most part modelling this will just lead to Class A having a method that calls Class B's methods with no real benefit and the downside of two function calls.

class A():

   b=B()

   __init__(self):
      self.a=[]

   def addToA(self,a):
      self.a.append(a)

   def addToB(a):
      # do something with self.a
      b.addToB(a)

What are people's thoughts on providing methods within A that is needed specifically when it alters B. however going to B directly otherwise:

z=A()
z.addToB(a)
z.b.methSpecificToB(x,y,z)

I feel I'm i'm breaking the encapsulation a little doing this however it makes more sense rather than simply providing superfluous methods..

Upvotes: 0

Views: 86

Answers (2)

Peter
Peter

Reputation: 3301

I would solve this with a @property decorator. When you set A.B, this will automatically set B.A.

class A:

    _b = None

    @property
    def b(self):
        return self._b

    @b.setter
    def b(self, b):
        self._b = b
        b.a = self

class B:

    a = None

foo = A()
bar = B()
foo.b = bar
bar.a == foo  # True
foo.b == bar  # True

What happens here is that when you set foo.b, it is saved as foo._b. (The underscore indicates a 'hidden' variable that is generally used for internal usage.) At the same time, bar.a is set to foo, enabling you to access foo from bar.

When trying to access foo.b, foo._b is returned instead. Since we set that to bar earlier, we also access bar from foo.

There are many tutorials on the Python properties. This one is kind'a OK.

Upvotes: 0

snakecharmerb
snakecharmerb

Reputation: 55630

I'd generally prefer the indirection of calling the method on A to call the method on B because it protects A's clients from changes in the implementation of A and B. For example, if later changes require that methodSpecificToB and some other method on B are called, I need only change A.addtoB, whereas if Z and other classes call B directly they all must be changed.

Ultimately it depends on the likelihood of B changing. If that's never going to happen then exposing B is probably ok, but if it's a possibility then indirection is safer.

Upvotes: 1

Related Questions