2

i have been reading about composition in python and after following some articles and answers here on stackoverlow i think i am able to get what it is and how it is implemented. but one question to which i am unable to find answer is why composition? (not comparing with benefits over inheritance). here is an example that i got from here:

class Salary:
    def __init__(self,pay):
        self.pay=pay

    def get_total(self):
       return (self.pay*12)

class Employee:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus
        self.obj_salary=Salary(self.pay)

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)


obj_emp=Employee(100,10)
print (obj_emp.annual_salary())

i would like to understand with a little realistic example where it would benefit by seperating two related classes( and what benefits exactly?)

anekix
  • 2,393
  • 2
  • 30
  • 57
  • `Salary` can be subclassed - *wage*, *tredicesima* etc. And an `Employee` type may *compose* any of the subclasses. – Moses Koledoye Jun 21 '17 at 15:40
  • @MosesKoledoye can't i use `pay` directly as an `object attribute` of `Employee` class? – anekix Jun 21 '17 at 15:42
  • 1
    That limits you to a numeric value. With the `Salary` class, you can track other relevant attributes relating to employee compensation. – Moses Koledoye Jun 21 '17 at 15:44

2 Answers2

4

using an extended version of your example

class Salary:
    def __init__(self,pay):
        self.pay=pay

    def get_total(self):
       return (self.pay*12)

    def increase(self):
        self.pay *= 1.1


class Employee:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus
        self.obj_salary=Salary(self.pay)

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)


obj_emp=Employee(100,10)
print (obj_emp.annual_salary())

calling employee.salary.increase makes much more sense than employee.increase

Also what if you needed multiple objects? would you inherit one of them or all of them leading to name possible name clashes?

class Game:
    def __init__(self):
        self.screens       = [LoadingScreen, MapScreen]        
        self.player        = Player()
        self.display       = Display()
        self.stats         = Stats(self.display)
        self.screenIndex   = self.player.getScreen()
        self.currentScreen = self.screens[self.screenIndex]()
        self.run()

* EDIT * after looking at this

but on looking it up again i find that increase could be renamed to increaseSalary so employee.increaseSalary() would make sense right?

you could simply move the increase to the employee class but what if you had a Manager class or a Boss class you would need to repeat the same code for each class

class Employee:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)

    def increase_salary(self):
        self.pay *= 1.1


class Manager:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)

    def increase_salary(self):
        self.pay *= 1.1

class Boss:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)

    def increase_salary(self):
        self.pay *= 1.1

OR only once

class Salary:
    def __init__(self,pay):
        self.pay=pay

    def get_total(self):
       return (self.pay*12)

    def increase(self, addition):
        self.pay *= addition

you could also use a class methods to find average, max, min etc a lot easier

Joshua Nixon
  • 1,379
  • 2
  • 12
  • 25
  • @JoshuaNixoxn thanks `employee.salary.increase` makes much more sense and also using multiple objects is an eye-opener for me :) – anekix Jun 21 '17 at 15:45
  • but on looking it up again i find that `increase` could be renamed to `increaseSalary` so `employee.increaseSalary()` would make sense right? – anekix Jun 21 '17 at 15:48
  • Sorry it's a little long but hope it helps – Joshua Nixon Jun 21 '17 at 15:55
0

ok i'll give it a try even though i'm kind of a noob. also there may be some points i'm missing but this is the way i like to think about it, any who, the answer:

because it gives you a lot of agility and allows you to 'compose' objects together that may not necessarily have a parent/child relationship (what in classical OOP is referred to as a IS-A type inheritance)

for example say you have a rifleclass. you want to add (or compose) attachments onto it.

how would you do this with inheritance? it wouldn't be very flexible.

so what you could do is define your attachments as there own classes, say a sight and a muzzle break class, and then declare instances of these attachment classes as fields in your rifle class and BAM you now have access to the methods defined in sight and muzzle break, just as when with inheritance a child class has access to its superclasses methods.

anyway to continue, you can see from this example how easy it would be to now create all sorts of weapon classes, like a howitzer, and if done properly you could declare instances of sight and muzzle break in howitzer.

notice that the relationship hierarchy we've created is completely flat.

to do all this with inheritance, you would define a base class, such as weapon with the same methods defined in sight and muzzle break. you would then crate child classes that branch out to rifle and to howitzer.

now imagine you don't want rifle to have a sight but a scope. you have to go through all these hoops and shenanigans in your base class to achieve this.

well with composition you would simply just create a new class scope (which could actually inherit from sight), remove the instances of sight from rifle and insert a field instance of scope. note that no changes were made to howitzer.

with all that said i still think inheritance is a useful tool to be exploited in the proper situations, just like composition.

mad.meesh
  • 2,558
  • 1
  • 13
  • 20