1

In a particular program I had written, I noticed I had a few classes with this pattern:

class IdObject:
    '''Objects with generated id properties'''
    def __init__(self, id_generator):
        self.id_generator = id_generator
        self.id = id_generator()

class Node(IdObject):
    '''Represents a node in the graph'''
    def __init__(self, id_generator):
        super().__init__(id_generator)

That is, there was particular property that I wanted a class to have, so I made a class that instantiated that property, and then just subclassed from that other class.

However, I realized I could do this for literally every other property. Having been a programmer for a while, doing that strikes me as just wrong, but it would be helpful for some more experienced and knowledgable programmers to help me discover exactly why doing that would be wrong.

For another example, it doesn't seem right to do:

class HasLength:
    def __init__(self, length):
        self.length = length

class HasWidth:
    def __init__(self, width):
        self.width = width

class Rectangle(HasLength, HasWidth):
    def __init__(self, length, width):
        HasLength.__init__(self, length)
        HasWidth.__init__(self, width)

This very much reminds me of Java's interfaces, but with properties.

So is it bad form to create a new class for each new property? Why or why not?

1
  • You can just do this with regular @property decorator when you need them, or write your own descriptor. Needing to do this is pretty rare in most code though, so if you have to do this frequently indicates a smell.
    – Lie Ryan
    Jul 4, 2019 at 2:56

3 Answers 3

11

Lot of popular languages don't support multiple inheritance, so that is possibly one reason.

I think the primary question here is that of complexity vs usefulness.

Our, the software developer's, job is to fight complexity. Keeping solutions as simple as possible while solving our problems. In your example, I don't see what advantage such structure would have. But it does increase the complexity. And structures that increase complexity while not providing anything of value should be shied away from.

2

A big reason for why you shouldn't create an object for each property is that (at least in all languages I'm familiar with) it would put the new object in a separate memory space. The implication is that you're paying the following additional price:

  1. Additional time to instantiate another object in a new location
  2. Memory overhead for the additional object
  3. Additional time on each memory access due to the extra dereferencing operation. This is also likelier to be a cache miss, since the new object could be stored in an entirely different area.
  4. Additional time to cleanup the additional object in the end (e.g. during a garbage collection cycle).

And as mentioned by Euphoric, you're also paying the cost of additional complexity, which would make it more difficult to maintain the code.

So unless you have a good reason for requiring the extra object, I would strongly suggest not paying the unnecessary price.

Indeed, unless you have another need for the IdObject class, I would suggest to rewrite your first example to something simpler like:

class Node:
    '''Represents a node in the graph'''
    def __init__(self, id_generator):
        self.id = id_generator()

Essentially, it all boils down to the YAGNI principle.

2

I agree with the top answer that inheritance is not the way to go here. But there's a more careful balancing act going on here. On the one hand, you don't want complex inheritance structures, so you should avoid doing a class-per-property approach.

But on the other hand, you also want to avoid primitive obsession.

Like most other smells, primitive obsessions are born in moments of weakness. “Just a field for storing some data!” the programmer said. Creating a primitive field is so much easier than making a whole new class, right? And so it was done. Then another field was needed and added in the same way. Lo and behold, the class became huge and unwieldy.

Putting it all together, the better approach is to indeed have a class for any reasonably independent data structure, but to use composition over inheritance.

In practice, this means that instead of (forigve the C# syntax, I don't know Java syntax by heart)

public class HasPostCode
{
    public string PostCode { get; set; }
}

public class Address : HasPostCode // Address inherits HasPostCode
{

}

You instead compose the classes without inheritance:

public class PostCode
{
    public string Code { get; set; }
}

public class Address
{
    public PostCode PostCode { get; set; }
}

In other words, the subclass is a property of the master class, the master class does not derive from the subclass.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.