Introduction
In our previous article, we looked at - Inheritance vs Polymorphism. Within this article, we will look at another OOP aspect - Inheritance vs Composition.
To explain this our example will be base upon a small ACL builder. This builder build an ACL for either an IOS or Junos based device. I appreciate the full config isn't included, but its adequate for the scope of this tutorial.
Inheritance
Inheritance establishes a relationship between two classes - parent (superclass) and child (subclass).
Child classes keep the attributes and methods of its parent, whilst also adding new attributes or methods of its own. Furthermore, the child class can also override methods of its parent.
Let us look at an example. Here JunosBuilder
and IosBuilder
extend the base class AccessListBuilder
. With each childclass overriding the build_acl
method, and inheriting the print_username
method.
class AccessListBuilder:
def print_username(self):
print("Cyril")
def build_acl(self, ipaddr):
raise NotImplementedError("Use a subclass!")
class JunosBuilder(AccessListBuilder):
def build_acl(self, ipaddr):
return "set security policies from-zone trust to-zone untrust source-address {}".format(ipaddr)
class IosBuilder(AccessListBuilder):
def build_acl(self, ipaddr):
return "access-list acl_permit permit ip host {}".format(ipaddr)
>>> aclbuilder = JunosBuilder()
>>> aclbuilder.print_username()
Cyril
>>> print(aclbuilder.build_acl("10.1.1.100"))
set security policies from-zone trust to-zone untrust source-address 10.1.1.100
>>> aclbuilder = IosBuilder()
>>> aclbuilder.print_username()
Cyril
>>> print(aclbuilder.build_acl("10.1.1.100"))
>>> access-list acl_permit permit ip host 10.1.1.100
Composition
Composition is defined as,
… the act of combining parts or elements to form a whole.
When it comes to OOP and Python, unlike inheritance we do not inherit from a base class. Instead, composition results in relationships being created between classes through the use of instance variables,[1] with these instance variables reference the other objects.
Let's look at our ACL builder, but this time built using composition. As you can see, no inheritance is performed. Instead, we create our builder objects, which are passed into our AccessListBuilder
via the set_provider
method.
Therefore by using composition is allows for decoupled code as classes and functions can work independently and do not depend on each other.
class JunosBuilder:
def build_acl(self, ipaddr):
return "set security policies from-zone trust to-zone untrust source-address {}".format(ipaddr)
class IosBuilder:
def build_acl(self, ipaddr):
return "access-list acl_permit permit ip host {}".format(ipaddr)
class AccessListBuilder:
device_builder = JunosBuilder()
def print_username(self):
print("Cyril")
def set_provider(self, provider):
self.device_builder = provider
def build_acl(self, ipaddr):
print(self.device_builder.build_acl(ipaddr))
>>> aclbuilder = AccessListBuilder()
>>> aclbuilder.print_username()
Cyril
>>> aclbuilder.set_provider(IosBuilder())
>>> aclbuilder.build_acl("10.1.1.100")
access-list acl_permit permit ip host 10.1.1.100
>>> aclbuilder.set_provider(JunosBuilder())
>>> aclbuilder.build_acl("10.1.1.100")
set security policies from-zone trust to-zone untrust source-address 10.1.1.100
References
"Classes and Objects II (Inheritance and Composition) Tutorials ...." https://www.hackerearth.com/practice/python/object-oriented-programming/classes-and-objects-ii-inheritance-and-composition/tutorial/. Accessed 24 Apr. 2019. ↩︎