Files
python-VM/movieposterporndownloader/__dev/design-patterns.txt

153 lines
6.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
To do : summarise the OOP principles
continue from pg20
# Encapsulation
## Interface
An interface is the public part of an object - which is open to interactions with other objects.
Interfaces look almost like classes, but only have methods (in other languages than python).
Interfaces aren't necessary in python because of multiple inheritance and duck typing. They are more used in Java where multiple inheritance isn't a thing/
Duck typing means that an operation does not formally specify the requirements that its operands have to meet, but just tries it out with what is given.
Thus, a dynamic type system as Python's always uses duck typing:
```python
def f(x):
x.Quack()
```
If f gets an x supporting a Quack(), everything is fine, if not, it will crash at runtime.
Interfaces can be implemented using Abstract base classes:
An interface is sort of like an empty muffin pan. It's a class file with a set of method definitions that have no code.
An implementation would be a class that depends on this interface that actually implements the methods that have been specified. If we were using abstract base clases, an implementation would be a class we create from this and write the abstract methods.
An abstract class is the same thing, but not all functions need to be empty. Some can have code. It's not strictly empty.
ABC:
```python
from abc import ABC, abstractmethod
class AccountingSystem(ABC):
@abstractmethod
def create_purchase_invoice(self, purchase):
pass
@abstractmethod
def create_sale_invoice(self, sale):
log.debug('Creating sale invoice', sale)
```
Create a normal subclass and override all abstract methods:
```python
class GizmoAccountingSystem(AccountingSystem):
def create_purchase_invoice(self, purchase):
submit_to_gizmo_purchase_service(purchase)
def create_sale_invoice(self, sale):
super().create_sale_invoice(sale)
submit_to_gizmo_sale_service(sale)
```
You can optionally have common implementation in the abstract methods as in create_sale_invoice(), calling it with super() explicitly in the subclass as above.
Instantiation of a subclass that does not implement all the abstract methods fails:
```python
class IncompleteAccountingSystem(AccountingSystem):
pass
```
Gives:
```
>>> accounting = IncompleteAccountingSystem()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class IncompleteAccountingSystem with abstract methods
create_purchase_invoice, create_sale_invoice
```
(see https://stackoverflow.com/a/51273196)
This means we can have a class that we only want to work with a certain type of object/class. We can create this class as an ABC and specify abstract methods. We can then create classes that implement this interface. Then, the parent class that we only want to work with a certain type will definitely work with the classes, which means we can use methods that we know will be present. See pg. 16.
## Encapsulation
Encapsulation is the ability of an object to hide parts of it state and behaviours from other objects - allowing you to expose only a limited interface to the rest of the program.
Encapsulating something means making it private - meaning it's only accessible from within the methods of it's own class.
You can also make something protected - this makes a member of a class available to subclasses as well.
In python this is through `_` and `__`.
## Polymorphism
Polymorphism is the ability of a program to detect the real class of an object and call its implementation, even when its real type is unknown in the current context.
You can think of a polymorphism as the ability of an object to pretend to be something else. This could be a class it extends or an interface it implements.
For example:
```python
bag = [Cat(), Dog()]
for animal in bag:
animal.make_sound()
```
Here Cat() and Dog() were pretending to be a generic animal. The code will try to invoke the method `make_sound()` without knowing if it exists. If it doesn't, it will raise an error.
# Relationships
## Inheritance
Inheritance: Class А inherits interface and implementation of class B but can extend it. Objects A can be treated as B. Class A depends on B.
The main benefit of inheritance is code reuse. If you need to create a new class that's only slightly different from an existing one, you don't need to repeat code. You can extend the current class by creating a subclass and adding any additional functionality into the subclass.
This subclass will inherit fields and methods of the superclass.
When you instantiate the subclass, think of it as "pulling" from the subclass, the subclass can define attributes on `self` which don't exist in it's scope, but when the subclass instantiates it will be able to use them.
Subclasses have the same interface as their parent class. You can't hide a method in a subclass if it was declared in the parent class.
If abstract methods are defined, they also have to be defined, even if they don't make sense in the subclass.
# Encapsulation
Identify the aspects of your application that vary and separate them from what stays the same.
The idea is to minimise the effect caused by changes.
You should isolate the parts of the program that vary into independent modules/components
This way, if a part of the code changes later on, you have protected the rest of the code from adverse affect.
## Encapsulation on a Method level
If a method is doing several things, highlight parts of it that are doing the different bits. You can then move things into other methods, and call them from within the current method.
E.g. if youre calculating tax on an order price, you can move this calculation step into a new method that takes a country, and returns the tax value. The original method can then call this new method to get its tax value.
## Encapsulation on a Class level
We know when a class starts to become too bloated if the intended purpose or responsability of the class is now confusing or not clear.
We can extract methods/variables and place them in a new class. Referencing these in the original class. It will reference the new methods and variables from the old class, meaning we have an aggregation relationship:
Aggregation: Object А knows about object B, and consists of B. Class A depends on B.