You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
2.6 KiB
Ruby

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# The Single Responsibility Principle is the most abstract of the bunch. It
# helps keep classes and methods small and maintainable. In addition to keeping
# classes small and focused it also makes them easier to understand.
# While we all agree that focusing on a single responsibility is important, its
# difficult to determine what a classs responsibility is. Generally, it is said
# that anything that gives a class a reason to change can be viewed as a
# responsibility. By change I am talking about structural changes to the class
# itself (as in modifying the code in the classs file, not the objects
# in-memory state).
# In the below class we have a single command interface that processes
# commission payments for deals. At first glance the class seems simple enough,
# but lets look at reasons we might want to change this class. Any change in
# how we calculate commissions would require a change to this class. We could
# introduce new commission rules or strategies that would cause our
# calculate_commission method to change. For instance, we might want to vary
# the percentage based on deal amount. Any change in the steps required to mark
# a deal as processed in the mark_deal_processed method would result in a change
# in the file as well. An example of this might be adding support for sending an
# email summary of a specific persons commissions after marking a deal
# processed. The fact that we can identify multiple reasons to change signals a
# violation of the Single Responsibility Principle.
class DealProcessor
attr_reader :deals
def initialize(deals)
@deals = deals
end
def process
deals.each do |deal|
# Here we calculate commission and create instance of Commission
Commission.create(deal: deal, amount: calculate_commission(deal))
mark_deal_processed
end
end
private
def mark_deal_processed
# Implementation
end
def calculate_commission(deal)
deal.amount * 0.05
end
end
class Commission
# Implementation
end
# Solution
class DealProcessor
attr_reader :deals
def initialize(deals)
@deals = deals
end
def process
deals.each do |deal|
# Now we call calculator in one operation, all logic now in it
CommissionCalculator.create_commission(deal) if mark_deal_processed
end
end
private
def mark_deal_processed
# Implementation
end
end
class CommissionCalculator
def self.create_commission(deal)
Commission.new(deal: deal, amount: calculate(deal))
end
private
def self.calculate(deal)
deal.amount * 0.05
end
end
class Commission
# Implementation
end