Skip to content

Instantly share code, notes, and snippets.

@janaki-sasidhar
Created July 13, 2021 12:57
Show Gist options
  • Save janaki-sasidhar/685ab5a4348b71aff1ace6b24e1dad0c to your computer and use it in GitHub Desktop.
Save janaki-sasidhar/685ab5a4348b71aff1ace6b24e1dad0c to your computer and use it in GitHub Desktop.
'''
SOLID DESIGN PRINCIPLES
[S]INGLE RESPONSIBILITY
[O]PEN / CLOSED
[L]ISKOV SUBSTITUTION
[I]NTERFACE SEGREGATION
[D]EPENDENCY INVERSION
'''
# CODE CONTENT FROM ARJAN CODE (https://www.youtube.com/watch?v=pTB30aXS77U)
# DO SUBSCRIBE TO HIS CHANNEL. GREAT CONTENT OVER THERE
# INITIAL CODE OF SALE SYSTEM (ORDDER AND PAYMENT HANDLING)
from typing import List
class Order:
items : List = []
quantities : List = []
prices : List = []
status : str = 'open'
def add_item(self,name,quantity,price) -> None:
self.items.append(name)
self.quantities.append(quantity)
self.price.append(price)
def total_price(self) -> float:
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.total
return total
def pay(self,payment_type,security_code) -> None:
if payment_type == 'debit':
print('PROCESSING DEBIT PAYMENT TYPE')
print(f'VERIFYING SECURITY CODE {security_code}')
self.status = 'paid'
elif payment_type == 'credit':
print('PROCESSING CREDIT PAYMENT TYPE')
print(f'VERIFYING SECURITY CODE {security_code}')
self.status = 'paid'
else:
raise Exception(f'Unknown payment type : {payment_type}')
'''
USING THE CLASS ABOVE
order = Order()
order.add_item('keyboard',1,50)
order.add_item('SSD',1,150)
order.add_item('USB CABLE',2,5)
print(order.total_price())
order.pay('debit','055050')
'''
############# SINGLE RESPONSIBILITY ####################
'''
CLASSES AND METHODS SHOULD HAVE SINGLE RESPONSIBILITY SO THAT THEY CAN BE RESUSED.
IN ABOVE CASE ORDER CAN HAVE add_item AND total_price BUT pay METHOD IS NOT NEEDED IN THERE .
ORDER HAS TOO MANY RESPONSIBILITIES
WE CAN MOVE THE pay METHOD TO A NEW CLASS SO IT CAN BE REUSED
'''
from typing import List
class Order:
items : List = []
quantities : List = []
prices : List = []
status : str = 'open'
def add_item(self,name,quantity,price) -> None:
self.items.append(name)
self.quantities.append(quantity)
self.price.append(price)
def total_price(self) -> float:
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.total
return total
class PaymentProcessor:
def pay_debit(self,order,security_code) -> None:
print('PROCESSING DEBIT PAYMENT TYPE')
print(f'VERIFYING SECURITY CODE {security_code}')
order.status = 'paid'
def pay_credit(self,order,security_code) -> None:
print('PROCESSING DEBIT PAYMENT TYPE')
print(f'VERIFYING SECURITY CODE {security_code}')
order.status = 'paid'
'''
USING THE CLASS ABOVE
order = Order()
order.add_item('keyboard',1,50)
order.add_item('SSD',1,150)
order.add_item('USB CABLE',2,5)
print(order.total_price())
payment_process = PaymentProcessor()
payment_process.pay_debit(order,'055050')
SWEET !!!
'''
################### OPEN / CLOSED #############################
'''
CODE WRITTEN SHOULD BE OPEN FOR EXTENSIBILITY LIKE INHERITING
BUT CLOSED FOR MODIFICATION SO WE SHOULDNT NEED TO MODIFY THE ORIGINAL CODE INI ORDER TO MODIFY
'''
'''
IN THE ABOVE EXAMPLE , IF WE WANT TO ADD ANOTHER PAYMENT METHOD , WE WANT TO MODIFY THE EXISTING PaymentProcessor Code.
'''
from abc import ABC ,abstractmethod
class Order:
items : List = []
quantities : List = []
prices : List = []
status : str = 'open'
def add_item(self,name,quantity,price) -> None:
self.items.append(name)
self.quantities.append(quantity)
self.price.append(price)
def total_price(self) -> float:
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.total
return total
class PaymentProcessor(ABC):
@abstractmethod
def pay(self,order,security_code):
pass
class DebitPaymentProcessor(PaymentProcessor):
def pay(self,order,security_code):
print('PROCESSING Debit type')
print(f'Verifying security code {security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def pay(self,order,security_code):
print('PROCESSING Credit type')
print(f'Verifying security code {security_code}')
order.status = 'paid'
class PayPalPaymentProcessor(PaymentProcessor):
def pay(self,order,security_code):
print('PROCESSING PayPal type')
print(f'Verifying security code {security_code}')
order.status = 'paid'
'''
USING THE CLASS ABOVE
order = Order()
order.add_item('keyboard',1,50)
order.add_item('SSD',1,150)
order.add_item('USB CABLE',2,5)
print(order.total_price())
payment_process = DebitPaymentProcessor()
payment_process.pay_debit(order,'055050')
SWEET !!!
'''
################## LISKOV SUBSTITUTION ######################
'''
If there are any objects in the code , we should be able to replace those objects with the instances of the subtypes or subclasses without altering the correctness of program.
The thing is the paypal doesnt work with security codes but email.
'''
from abc import ABC ,abstractmethod
class Order:
items : List = []
quantities : List = []
prices : List = []
status : str = 'open'
def add_item(self,name,quantity,price) -> None:
self.items.append(name)
self.quantities.append(quantity)
self.price.append(price)
def total_price(self) -> float:
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.total
return total
class PaymentProcessor(ABC):
@abstractmethod
def pay(self,order):
pass
class DebitPaymentProcessor(PaymentProcessor):
def __init__(self,security_code):
self.security_code = security_code
def pay(self,order):
print('PROCESSING Debit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self,security_code):
self.security_code = security_code
def pay(self,order):
print('PROCESSING Credit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class PayPalPaymentProcessor(PaymentProcessor):
def __init__(self,email):
self.email = email
def pay(self,order):
print('PROCESSING PayPal type')
print(f'Verifying security code {self.email}')
order.status = 'paid'
'''
USING THE CLASS ABOVE
order = Order()
order.add_item('keyboard',1,50)
order.add_item('SSD',1,150)
order.add_item('USB CABLE',2,5)
print(order.total_price())
payment_process = PayPalPaymentProcessor('[email protected]')
payment_process.pay_debit(order)
SWEET !!!
'''
##################### INTERFACE SEGGREGATION ##########################
'''
SEVERAL SPECIFIC INTERFACES INSTEAD OF ONE GENERAL INTERACE
'''
# modifying original code to add sms verification and then working on seggregation
from abc import ABC ,abstractmethod
class Order:
items : List = []
quantities : List = []
prices : List = []
status : str = 'open'
def add_item(self,name,quantity,price) -> None:
self.items.append(name)
self.quantities.append(quantity)
self.price.append(price)
def total_price(self) -> float:
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.total
return total
class PaymentProcessor(ABC):
@abstractmethod
def pay(self,order):
pass
@abstractmethod
def auth_sms(self):
pass
class DebitPaymentProcessor(PaymentProcessor):
def __init__(self,security_code):
self.security_code = security_code
self.verified = False
def auth_sms(self,code):
print('VERIFYING SMS CODE {code}')
self.verified=True
def pay(self,order):
print('PROCESSING Debit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self,security_code):
self.security_code = security_code
def auth_sms(self,code):
raise Exception('CREDIT CARD PAYMNETS DOESNT SUPPORT SMS CODE AUTHORIZATION')
def pay(self,order):
print('PROCESSING Credit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class PayPalPaymentProcessor(PaymentProcessor):
def __init__(self,email):
self.email = email
self.verified = False
def auth_sms(self,code):
print('VERIFYING SMS CODE {code}')
self.verified=True
def pay(self,order):
print('PROCESSING PayPal type')
print(f'Verifying security code {self.email}')
order.status = 'paid'
'''
NOW WE DONT WANT TO RAISE EXCEPTION FOR CREDITCARD BUT GRACEFULLY DO THINGS .
IN BELOW WE MODIFIED SO WE BEAUTIFULLY SEGGREGATED DEBIT , PAYPAL WITH CREDIT WITH EXTENDING FROM MULTIPLE SUBCLASSES
'''
from abc import ABC ,abstractmethod
class Order:
items : List = []
quantities : List = []
prices : List = []
status : str = 'open'
def add_item(self,name,quantity,price) -> None:
self.items.append(name)
self.quantities.append(quantity)
self.price.append(price)
def total_price(self) -> float:
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.total
return total
# auth_sms not needed here
class PaymentProcessor(ABC):
@abstractmethod
def pay(self,order):
pass
# we used auth_sms here but not pay because its inherited by default
class PaymentProcessor_SMS(PaymentProcessor):
@abstractmethod
def auth_sms(self):
pass
class DebitPaymentProcessor(PaymentProcessor_SMS):
def __init__(self,security_code):
self.security_code = security_code
self.verified = False
def auth_sms(self,code):
print('VERIFYING SMS CODE {code}')
self.verified=True
def pay(self,order):
print('PROCESSING Debit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self,security_code):
self.security_code = security_code
def pay(self,order):
print('PROCESSING Credit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class PayPalPaymentProcessor(PaymentProcessor_SMS):
def __init__(self,email):
self.email = email
self.verified = False
def auth_sms(self,code):
print('VERIFYING SMS CODE {code}')
self.verified=True
def pay(self,order):
print('PROCESSING PayPal type')
print(f'Verifying security code {self.email}')
order.status = 'paid'
'''
USING COMPOSITION INSTEAD OF MULTIPLE SUBCLASSES. LEARN ABOUT COMPOSITION AND WHY ITS BETTER THAN INHERITANCE
'''
from abc import ABC ,abstractmethod
class Order:
items : List = []
quantities : List = []
prices : List = []
status : str = 'open'
def add_item(self,name,quantity,price) -> None:
self.items.append(name)
self.quantities.append(quantity)
self.price.append(price)
def total_price(self) -> float:
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.total
return total
class SMSAuth:
authorized = False
def verify_code(self,code):
print(f'verifying code {code}')
self.authorized = True
def is_authorized(self) -> bool:
return self.authorized
class PaymentProcessor(ABC):
@abstractmethod
def pay(self,order):
pass
class DebitPaymentProcessor(PaymentProcessor):
def __init__(self,security_code , authorizer: SMSAuth):
self.authorizer = authorizer
self.security_code = security_code
def pay(self,order):
if not self.authorizer.is_authorized():
raise Exception('not authorized')
print('PROCESSING Debit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self,security_code):
self.security_code = security_code
def pay(self,order):
print('PROCESSING Credit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class PayPalPaymentProcessor(PaymentProcessor):
def __init__(self,email,authorizer: SMSAuth):
self.email = email
self.authorizer = authorizer
def pay(self,order):
if not self.authorizer.is_authorized():
raise Exception('not authorized')
print('PROCESSING PayPal type')
print(f'Verifying security code {self.email}')
order.status = 'paid'
'''
USING THE CLASS ABOVE
order = Order()
order.add_item('keyboard',1,50)
order.add_item('SSD',1,150)
order.add_item('USB CABLE',2,5)
print(order.total_price())
authorizer = SMSAuth()
processor = DebitPaymentProcessor('002020',authorizer)
authorizer.verify_code(465389)
processor.pay(order)
SWEET !!!
'''
############ DEPENDENCY INVERSION #############
from abc import ABC ,abstractmethod
class Order:
items : List = []
quantities : List = []
prices : List = []
status : str = 'open'
def add_item(self,name,quantity,price) -> None:
self.items.append(name)
self.quantities.append(quantity)
self.price.append(price)
def total_price(self) -> float:
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.total
return total
class Authorizer(ABC):
@abstractmethod
def is_authorized(self) -> bool:
return self.authorized
class SMSAuth(Authorizer):
authorized = False
def verify_code(self,code):
print(f'verifying code {code}')
self.authorized = True
def is_authorized(self) -> bool:
return self.authorized
class ROBOTAuth(Authorizer):
authorized = False
def not_a_robot(self):
print('ARE YOU A ROBOT ? NO')
self.authorized =True
def is_authorized(self) -> bool:
return self.authorized
class PaymentProcessor(ABC):
@abstractmethod
def pay(self,order):
pass
class DebitPaymentProcessor(PaymentProcessor):
def __init__(self,security_code , authorizer: Authorizer):
self.authorizer = authorizer
self.security_code = security_code
def pay(self,order):
if not self.authorizer.is_authorized():
raise Exception('not authorized')
print('PROCESSING Debit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class CreditPaymentProcessor(PaymentProcessor):
def __init__(self,security_code):
self.security_code = security_code
def pay(self,order):
print('PROCESSING Credit type')
print(f'Verifying security code {self.security_code}')
order.status = 'paid'
class PayPalPaymentProcessor(PaymentProcessor):
def __init__(self,email,authorizer: Authorizer):
self.email = email
self.authorizer = authorizer
def pay(self,order):
if not self.authorizer.is_authorized():
raise Exception('not authorized')
print('PROCESSING PayPal type')
print(f'Verifying security code {self.email}')
order.status = 'paid'
'''
USING THE CLASS ABOVE
order = Order()
order.add_item('keyboard',1,50)
order.add_item('SSD',1,150)
order.add_item('USB CABLE',2,5)
print(order.total_price())
authorizer = ROBOTAuth()
processor = DebitPaymentProcessor('002020',authorizer)
authorizer.not_a_robot()
processor.pay(order)
SWEET !!!
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment