-
Capture, group info, data and related functionality into 'objects'
-
OOP world viewed as collection as objects
-
Abstract data like unique data structures, user accounts etc
-
Each object responsible for it's own data and operations performed in that data (scope)
-
Objects can interact with eachother
- A class
- Class name
- Attribute
- All of the information share dby any object of this class type
- Methods
- Code associated with the class tha tallows you to access or change it's attributes
- A class is not an object itself.
- Very easy to reuse a calss and create multiple objects of that class
- Classes are in itself not an object, more of a template for one
- To create an object from a class, we go through a process called instansiation (initialising a class into an object)
ClassName()
--> Constructor
--> Attributes set (variables local to the class and any instantised objects from this class)
--> SomeAttribute(String)
--> AnotherAttribute(Integer)
--> Methods
--> myMethod()
--> anotherMethod()
Above is an example of a class, a class itself does not serve much of a purpose, it's like a 'template' for an object
new ClassName(SomeAttribute, AnotherAttribute) -> something
Above is an example of us using that class to create an object called 'something'. We can call methods and set attributes of something based of the attributes and methods defined in the class, ClassName.
- Implementation varies language to language (surprise)
- Similar structure between all languages
- Langauges class keyword then class name
- Break out of the indendation or a marker that indicates the end of the class
- Attributes for the class
- Parameters and code for the instantiation of the class (e.g. _init_ in python)
- Called a "constructor" method
- Can be used to set local attributes before methods used
Example of a class without any paramters in Python:
"""
Example of a class being implemented in python
"""
class SomeClass(object): #A class is pretty much a template of an object
def __init__(self):
#self in python is the local scope of an object after instantised
self.somevar = "Something"
Example of a class with parameters in Python:
class SomeClass(object):
def __init__(self,somePassedVariable):
self.somevar = somePassedVariable # This variable is now locally available in any instantised object made from this class
Example of a class with a single method being instantised into it's own object:
class SomeClass(object):
def __init__(self,somePassedVariable):
self.somevar = somePassedVariable
def myMethod(self):
print(self.somevar)
myObject = SomeClass()
>> Parameter error
# You must always try to initialise a class with all required parameters inside of it's constructor method, unless the constructor provides a default
myObject = SomeClass("A string")
>> myObject -> new SomeClass ("A string")
# We now have an object stored inside myObject which represents a copy of SomeClass
myObject.myMethod()
>> "A string"
# Thanks to our class, the object has a single method which uses a variable stored locally inside the class when we initialised it, here we call a method which utilises that variable
A static function is a function which never leaves the scope of this, the local scope to that instance of an object (from a class).
class SomeClass(object):
def __init__(self,someVar):
self.somevar = someVar
@staticmethod
def myStaticMethod():
return "I never interact with anything in the local scope"
def myNoneStaticMethod(self):
return self.somevar
example = SomeClass("I do!")
example.myStaticMethod()
>> "I never interact with anything in the local scope"
example.myNoneStaticMethod()
>> "I do!"
For examples in this section I'll extend from the class here:
myClass()
--> Constructor
--> SomeAttribute(String)
--> AnotherAttribute(Integer)
--> Methods
--> myMethod()
> return "Hello, world!"
--> anotherMethod(varPassedIntoMethod)
> return varPassedIntoMethod + self.AnotherAttribute
#Implementation of the above class
new myClass(
SomeAttribute = "hello"
AnotherAttribute = 2
) -> something
something.myMethod()
>> "Hello, world!"
something.anotherMethod(3)
>> 5
One can extend an existing class, using a class as a template for another class.
This decreases code replication and allows for simpler implementation of objects. Having a generic class makes it easier to implement multiple similar classes- we can reuse an existing class, using it's attributes and methods, without affecting the original code.
anotherClass(myClass)
# This extends myClass - we need a class with the same methods as myClass, which also carries another method for something else we may need to do
--> Constructor
--> VeryImportantAttribute(String)
--> Methods
--> veryImportantExtraMethod()
> return self.VeryImportantAttribute + ", world!"
#Implementation of the above class
new anotherClass(
SomeAttribute = "hello"
AnotherAttribute = 2
VeryImportantAttribute = "goodbye"
) -> something
something.myMethod()
>> "Hello, world!"
something.anotherMethod(3)
>> 5
something.veryImportantExtraMethod()
>> "Goodbye, world!"
Here anotherClass
has inherited the same methods and attributes of myClass, we only add the new parts of the class we require.
This is called a subclass
- a child which extends another class. Whereas myClass
(in context of anotherClass
), is a superclass
- a parent to a, or multiple, child classes.
A subclass and superclass is always context related, we could have more classes inherited from anotherClass
, these classes would see anotherClass
as it's super class.
There is no limit1 to how far you may branch a class.
1 Theoretically in implementation, there may be limits in specific languages, or proposed by system resources ↩
We can override standard inheritance by simply having an attribute or method which is identified the same way in a subclass
as it's superclass
For example if anotherClass.myMethod
was defined when creating the extension of myClass
, the implementation of myClass.myMethod
would not be inherited by anotherClass
.
anotherClass(myClass)
# This extends myClass - we need a class with the same methods as myClass, which also carries another method for something else we may need to do
--> Constructor
--> VeryImportantAttribute(String)
--> Methods
--> veryImportantExtraMethod()
> return self.VeryImportantAttribute + ", world!"
--> myMethod()
> return "This is completely unrelated to myClass"
#Implementation of the above class
new anotherClass(
SomeAttribute = "hello"
AnotherAttribute = 2
VeryImportantAttribute = "goodbye"
) -> something
something.myMethod()
>> "This is completely unrelated to myClass"
something.anotherMethod(3)
>> 5
something.veryImportantExtraMethod()
>> "Goodbye, world!"
An original method can still be obtained in most object-oriented programming langauges. This is done by called the superclass
inside the subclass
, as the original structure of the parent should always be stored.
something.super.myMethod()
>> "Hello, world!"
class myClass(object):
def __init__(self,SomeAttribute,AnotherAttribute) -> None: # A superclass to the other classes
self.SomeAttribute = SomeAttribute
self.AnotherAttribute = AnotherAttribute
@staticmethod
def myMethod()
return "Hello, world!"
def anotherMethod(varPassedIntoMethod):
return varPassedIntoMethod + self.AnotherAttribute
class anotherClass(myClass): # A subclass showing inheritance
def __init__(self,SomeAttribute,AnotherAttribute,VeryImportantAttribute):
super().__init__() # In python to avoid rewriting the superclass constructor method, we can call it
self.VeryImportantAttribute = VeryImportantAttribute
def veryImportantExtraMethod(self):
return self.VeryImportantAttribute + ", world!"
class myOverrideClass(myClass): # A subclass showing overridden methods
def __init__(self,SomeAttribute,AnotherAttribute): # A superclass to the other classes
super().__init__()
@staticmethod
def myMethod(self):
return "This is completely unrelated to myClass"
exampleStandardClass = myClass("Something",123)
myClass.myMethod()
>> "Hello, world!"
myClass.anotherMethod(3)
>> 125
exampleInheritedClass = anotherClass("Something",321,"Goodbye")
exampleInheritedClass.myMethod()
>> "Hello, world!"
exampleInheritedClass.anotherMethod(2)
>> 323
exampleInheritedClass.veryImportantMethod("aaaa", 1337)
>> "Goodbye, world!"
overrideClass = myOverrideClass()
overrideClass.myClass()
>> "This is completely unrelated to myClass"
overrideClass.super().myClass()
>> "Hello, world!"
overrideClass.anotherMethod(1)
>> 1338
Encapsulation is about protecting certain contents of an initialised class, an object.
- The "bundling of data with the methods that operate on and restrict direct access to it"
- Is used to hide value sor states of an obejct
- Encapsulised attributes should only be accessible or changable by the methods provided by the object
- Keeps data related to an object safe- can't be accidentally modified by other methods
- Protected attributes act like a variable/attribute stored locally somewhere else, attempting to access it will return an error/exception in the implementation like it doesn't exist (unless accessed through the method required)
Implementation:
- You must supply methods if you want an objects internal attributes to be read/written
- An objects methods are usually public, not private
- The methods are the part of of the same object, so it's private attributes are available
- Every language has it's own unique way to implement protected members
class Person:
def __init__(self):
self.name = 'Some'
self.__lastname = 'Person'
def PrintName(self):
return self.name +' ' + self.__lastname#Inside the class, or once instantised an object, we can view and edit __lastname
#Outside class
P = Person()
print(P.name)
>> "Some"
print(P.PrintName())
>> "Some Person"
print(P.__lastname)#When accessing this outside the object however, not going through a method, we get an error as if the attribute does not exist
>> Exception: AttributeError: 'Person' object has no attribute '__lastname'
- Polymorphism just means many forms
- You're likely to of used it before
- Example in Python
a = "Hello" b = ", world! print(a+b) # String concatentation >> "Hello, world!" a = 1 b = 2 print(a+b) # Math operator >> 3
- As you can see above, in both cases of
print(a+b)
we had completely different operations
- Example in Python
- OOP has two types of polymorphism
- Static
- Multiple methods of the same name, with different parameters in the same class
- Also known as "method overloading"
- In order for this to work it must differ in at least one of the following ways:
- They need to have a different number of parameters
- The types of parameters are different
- They expect the parameters in a different order (bad practice)
- Dynamic
- Some things to remember
- A subclass can override a superclass
- An overriden superclass means we can completely replace or customise the behaviour of that specific method we override, acting like a completely new method
- Overriding a method of a superclass in a subclass is a form of polymorphism
- This is as they share the same name and parameters, but have different functionality depending on how they're implemented
- Some things to remember
- Static
A class is more of a template for an object which could be instantised in the future.
Inheritence is where you create a class as a subclass of another class, allowing it to have similar attributes and methods, which can be re-used or altered.
To replace a method which is unfit for the usecase of a more specific/specialised implementation of a class.
Encapsulation allows us to protect attributes inside of an instantised class (an object), and therefore means we can not accidentally modify an attribute we wish to protect or of high importance, forcing us to interact with it through a method.
Polymorphism allows us to have different use-cases of a single method, allowing us to implement some code in the same way for all uses, but run different operations on fed data.