0

Objects of my class A are similar to network connections, i.e. characterized by a handle per connection opened. That is, one calls different methods with a handle (a particular connection) as argument. My class A (python 2.7) looks like:

class A(object):
  def __init__(self, *args):
    ... some init
  def my_open(self, *args)
    handle = ... some open
    return handle
  def do_this(self, handle, *args):
    foo_this(handle, args)
  def do_that(self, handle, *args):
    foo_that(handle, args)

A typical usage is

a = A(args)
handle = a.my_open(args2)
a.do_this(handle, args3)

Now, in a particular situation, there is only one connection to take care of, i.e. one handle in play. So, it is reasonable to hide this handle but keep class A for the more general situation. Thus, my first thoughts on a class B which "is a" kind of class A (usage stays the same but hides handle) are:

class B(A):
  def __init__(self, *args):
    super(A, self).__init__(args)
    self.handle = None
  def my_open(self, *args):
    self.handle = super(A, self).__init__(args)
  def do_this(self, *args):
    super(A, self).do_this(self.handle, args)
  def do_that(self, *args):
    super(A, self).do_that(self.handle, args)

Unfortunately, in my opinion, it seems very convoluted. Any better ideas?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
José
  • 1
  • For consistency sake, I'd **just return that one handle**, and make it a singleton. – Martijn Pieters Nov 24 '17 at 10:00
  • And really, you need to put the methods `do_this()` and `do_that()` *on the handle object*. That means: `handle = a.my_open(args2)`, then `handle.do_this(args3)`. – Martijn Pieters Nov 24 '17 at 10:02
  • Your system built so that you can open a handle with one A object and use it with another or use the first A with another handle. It is a mess as for me. Make it more organized. – Zefick Nov 24 '17 at 10:06

2 Answers2

1

Objects of my class A are similar to network connections, i.e. characterized by a handle per connection opened. That is, one calls different methods with a handle (a particular connection) as argument.

You have inverted the responsibility. The handle object holds the state the methods operate on, so those methods should live on the handle, not the factory.

Move your methods to the handle object, so the API becomes:

a = A(args)
handle = a.my_open(args2)
handle.do_this(args3)

The class implementing the handle() could retain a reference to a if so required; that's an implementation detail that the users of the API don't need to worry about.

You then return new handles, or a singleton handle, as needed.

By moving responsibility to the handle object, you can also make your factory produce handles of entirely different types, depending on the arguments. A(args).my_open(args2) could also produce the singleton handle that you now have class B for, for example.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

How about a class for the handle itself?:

class Handle(object):
    def __init__(self, *args):
        # init ...
        self._handle = low_level_handle
    def do_this(self, *args):
        # do_this ...
        pass
    def do_that(self, *args):
        # do_that
        pass

class A(object):
    def __init__(self, *args):
       # init ...
    def my_open(self, *args):
       handle = Handle(args)
       # handle post-processing (if any)
       return handle

e.g.:

a = A(args)
handle = a.my_open(args2)
handle.do_this(args3)
Matias Cicero
  • 25,439
  • 13
  • 82
  • 154