Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Built inital directory structure for design pattern implementations to follow #59

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ written correctly.
- [Data Compression](src/standard_libraries/test_zlib.py) (`zlib` library)
12. **User input**
- [Terminal input](src/user_input/test_input.py) (`input` statement)
13. **Design Patterns**
- [Creational Patterns](src/design_patterns/creational_patterns/test_creational_pattern.py) (`creational` design pattern)
- [Structural Patterns](src/design_patterns/structural_patterns/test_structural_pattern.py) (`structural` design pattern)
- [Behavioral Patterns](src/design_patterns/behavioral_patterns/test_behavioral_pattern.py) (`behavioral` design pattern)
- [Concurrency Patterns](src/design_patterns/concurrency_patterns/test_concurrency_pattern.py) (`concurrency` design pattern)

## Prerequisites

Expand Down
86 changes: 86 additions & 0 deletions src/design_patterns/behavioral_patterns/test_behavioral_pattern.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Behavioral Patterns

@see https://legacy.python.org/workshops/1997-10/proceedings/savikko.html#gof
@see https://www.toptal.com/python/python-design-patterns
@see https://github.com/faif/python-patterns

Being one of software engineering's main fields of work, software design patterns are a general, reusable solution to a commonly occurring software design problem.
A design pattern can be understood as a description or template, guiding an engineer when solving a problem through best practices and well-known standards.
On top, design patterns make code easier to understand and maintainable.

Behavioral design patterns - a subcategory of design patterns - are design patterns that identify common communication patterns among objects.
By doing so, these patterns increase flexibility in carrying out inter-object-communication.

Typical Behavioral design patterns are:

- Blackboard
- Command
- Chain of Responsibility
- Interpretar
- Iterator
- Mediator
- Memento
- Observer
- Protocol Stack
- State
- Strategy
- Visitor
- Scheduled-Task

Note: Design patterns fit a special role in python because everything in python is an object, even functions are objects. Some design patterns are already implemented in python,
others are not necessary due to python's nature.
"""


# Chain of Responsibility
class ContentFilter(object):
"""Every code element has one - and only one - specific job"""

def __init__(self, filters=None):
self._filters = list()
if filters is not None:
self._filters += filters

def filter(self, content):
for filter in self._filters:
content = filter(content)
return content

filter = ContentFilter([
offensive_filter,
ads_filter,
porno_video_filter])

filtered_content = filter.filter(content)


# Command
class RenameFileCommand(object):
"""Command execution when needed"""

def __init__(self, from_name, to_name):
self._from = from_name
self._to = to_name

def execute(self):
os.rename(self._from, self._to)

def undo(self):
os.rename(self._to, self._from)

class History(object):
def __init__(self):
self._commands = list()

def execute(self, command):
self._commands.append(command)
command.execute()

def undo(self):
self._commands.pop().undo()

history = History()
history.execute(RenameFileCommand('docs/cv.doc', 'docs/cv-en.doc'))
history.execute(RenameFileCommand('docs/cv1.doc', 'docs/cv-bg.doc'))
history.undo()
history.undo()
73 changes: 73 additions & 0 deletions src/design_patterns/creational_patterns/test_creational_pattern.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Creational Patterns

@see https://legacy.python.org/workshops/1997-10/proceedings/savikko.html#gof
@see https://www.toptal.com/python/python-design-patterns
@see https://github.com/faif/python-patterns

Being one of software engineering's main fields of work, software design patterns are a general, reusable solution to a commonly occurring software design problem.
A design pattern can be understood as a description or template, guiding an engineer when solving a problem through best practices and well-known standards.
On top, design patterns make code easier to understand and maintainable.

Creational design patterns - a subcategory of design patterns - are patterns dealing with object creation mechanisms (often in OOP environments),
trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or in added complexity to the design.
Creational design patterns aim to solve this problem by somehow controlling this object creation.

Typical Creational design patterns are:

- Abstract Factory
- Builder
- Dependency Injection
- Factory Method
- Lazy Initialization
- Multition
- Object Pool
- Prototype
- Singleton

Note: Design patterns fit a special role in python because everything in python is an object, even functions are objects. Some design patterns are already implemented in python,
others are not necessary due to python's nature. Creational patterns are rather uncommon in python, since it already is a very dynamic language.
"""


# Singleton
class Logger(object):
"""Making sure that only one instance of a given class exists during runtime"""
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_logger'):
cls._logger = super(Logger, cls
).__new__(cls, *args, **kwargs)
return cls._logger


# Dependency Injection
class Command:
"""Creating object outside of where it is used"""

def __init__(self, authenticate=None, authorize=None):
self.authenticate = authenticate or self._not_authenticated
self.authorize = authorize or self._not_autorized

def execute(self, user, action):
self.authenticate(user)
self.authorize(user, action)
return action()

if in_sudo_mode:
command = Command(always_authenticated, always_authorized)
else:
command = Command(config.authenticate, config.authorize)

command.execute(current_user, delete_user_action)


# Alternative Dependency Injection
command = Command()

if in_sudo_mode:
command.authenticate = always_authenticated
command.authorize = always_authorized
else:
command.authenticate = config.authenticate
command.authorize = config.authorize

command.execute(current_user, delete_user_action)
117 changes: 117 additions & 0 deletions src/design_patterns/structural_patterns/test_structural_pattern.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""Structural Patterns

@see https://legacy.python.org/workshops/1997-10/proceedings/savikko.html#gof
@see https://www.toptal.com/python/python-design-patterns
@see https://github.com/faif/python-patterns

Being one of software engineering's main fields of work, software design patterns are a general, reusable solution to a commonly occurring software design problem.
A design pattern can be understood as a description or template, guiding an engineer when solving a problem through best practices and well-known standards.
On top, design patterns make code easier to understand and maintainable.

Structural design patterns - a subcategory of design patterns - are patterns dealing with object relations. They ease the design by identifying a simple way to
realize relationships among entities.

Typical Structural design patterns are:

- Adapter
- Aggregate
- Facade
- Bridge
- Flyweight
- Decorator
- Marker
- Proxy

Note: Design patterns fit a special role in python because everything in python is an object, even functions are objects. Some design patterns are already implemented in python,
others are not necessary due to python's nature.
"""


# Facade
class Car(object):
"""Streamlining an interface by creating a client-facing facade which hides multiple other objects"""

def __init__(self):
self._tyres = [Tyre('front_left'),
Tyre('front_right'),
Tyre('rear_left'),
Tyre('rear_right'), ]
self._tank = Tank(70)

def tyres_pressure(self):
return [tyre.pressure for tyre in self._tyres]

def fuel_level(self):
return self._tank.level


# Adapter --> similar to Bridge and Proxy
import socket

class SocketWriter(object):
"""Altering an interface by translating a new interface to a known one"""

def __init__(self, ip, port):
self._socket = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
self._ip = ip
self._port = port

def write(self, message):
self._socket.send(message, (self._ip, self._port))

def log(message, destination):
destination.write('[{}] - {}'.format(datetime.now(), message))

upd_logger = SocketWriter('1.2.3.4', '9999')
log('Something happened', udp_destination)


# Decorator
"""Introducing additional functionality without inheritance"""

def execute(action, *args, **kwargs):
return action()

def autheticated_only(method):
def decorated(*args, **kwargs):
if check_authenticated(kwargs['user']):
return method(*args, **kwargs)
else:
raise UnauthenticatedError
return decorated

def authorized_only(method):
def decorated(*args, **kwargs):
if check_authorized(kwargs['user'], kwargs['action']):
return method(*args, **kwargs)
else:
raise UnauthorizeddError
return decorated

execute = authenticated_only(execute)
execute = authorized_only(execute)

# We can also use the core-python integrated syntax
def autheticated_only(method):
def decorated(*args, **kwargs):
if check_authenticated(kwargs['user']):
return method(*args, **kwargs )
else:
raise UnauthenticatedError
return decorated


def authorized_only(method):
def decorated(*args, **kwargs):
if check_authorized(kwargs['user'], kwargs['action']):
return method(*args, **kwargs)
else:
raise UnauthorizedError
return decorated


@authorized_only
@authenticated_only
def execute(action, *args, **kwargs):
return action()