###Choose Names at the Appropriate Level of Abstraction
Choose Names at the Appropriate Level of Abstraction
###Choose Names at the Appropriate Level of Abstraction
Choose Names at the Appropriate Level of Abstraction
What if XmlParser
changes? What if we wanted to use a different kind of Parser? What if we wanted to construct a Fake object for testing and pass that to MacbethAnalyzer
? These are issues thatrelated to the Dependency Inversion Principle aims to resolve.
What if XmlParser
changes? What if we wanted to use a different kind of Parser? What if we wanted to construct a Fake object for testing and pass that to MacbethAnalyzer
? These are issues that the Dependency Inversion Principle aims to resolve.
What if XmlParser
changes? What if we wanted to use a different kind of Parser? What if we wanted to construct a Fake object for testing and pass that to MacbethAnalyzer
? These are issues related to the Dependency Inversion Principle.
Having completed a working implementation, I notice that ParserParser
is only responsible for parsing Xml, which has a clear dependency in the constructor:
The given problem is small, but it's easy to imagine a larger project where we parse from several sources of varying formats beyond XML. It seems clear that the Parser classParser
isn't specific enough and should be more meaningfully distinguished by renaming to XmlParserXmlParser
.
Dependency Inversion Principle
The constructor of MacbethAnalzyer
has tight coupling in the dependency to the low-level implementation details of XmlParser
:
class MacbethAnalyzer
@parser = XmlParser.new(MACBETH_URL)
@speaker_line_counts = analyze_speaker_line_counts
end
What if XmlParser
changes? What if we wanted to use a different kind of Parser? What if we wanted to construct a Fake object for testing and pass that to MacbethAnalyzer
? These are issues that the Dependency Inversion Principle aims to resolve.
The solution here is to use "dependency injection" to inject Parser
into MacbethAnalyzer
:
class MacbethAnalyzer
attr_reader :speaker_line_counts
MACBETH_URL = "http://www.ibiblio.org/xml/examples/shakespeare/macbeth.xml"
IGNORE_SPEAKERS = %w(ALL)
def initialize(parser)
@parser = parser
@speaker_line_counts = analyze_speaker_line_counts
end
def analyze_speaker_line_counts
speaker_line_counts = Hash.new(0)
speakers = parser.parse(query: '//SPEAKER')
speakers.map do |speaker|
unless IGNORE_SPEAKERS.include? speaker.text
speaker_line_counts[speaker.text] += parser.parse(
node: speaker, query: '../LINE').count
end
end
speaker_line_counts
end
private
attr_reader :parser
end
if __FILE__ == 0ドル
analyzer = MacbethAnalyzer.new(XmlParser.new(MACBETH_URL))
Printer.print_hash_val_capitalized_key(
hash: analyzer.speaker_line_counts, filter: 'ALL')
end
Now MacbethAnalyzer
doesn't depend on a lower-level implementation; we use duck typing to make things flexible, removing the dependency and resulting in much more loosely coupled code.
Having completed a working implementation, I notice that Parser is only responsible for parsing Xml, which has a clear dependency in the constructor:
The given problem is small, but it's easy to imagine a larger project where we parse from several sources of varying formats beyond XML. It seems clear that the Parser class isn't specific enough and should be more meaningfully distinguished by renaming to XmlParser.
Having completed a working implementation, I notice that Parser
is only responsible for parsing Xml, which has a clear dependency in the constructor:
The given problem is small, but it's easy to imagine a larger project where we parse from several sources of varying formats beyond XML. It seems clear that classParser
isn't specific enough and should be more meaningfully distinguished by renaming to XmlParser
.
Dependency Inversion Principle
The constructor of MacbethAnalzyer
has tight coupling in the dependency to the low-level implementation details of XmlParser
:
class MacbethAnalyzer
@parser = XmlParser.new(MACBETH_URL)
@speaker_line_counts = analyze_speaker_line_counts
end
What if XmlParser
changes? What if we wanted to use a different kind of Parser? What if we wanted to construct a Fake object for testing and pass that to MacbethAnalyzer
? These are issues that the Dependency Inversion Principle aims to resolve.
The solution here is to use "dependency injection" to inject Parser
into MacbethAnalyzer
:
class MacbethAnalyzer
attr_reader :speaker_line_counts
MACBETH_URL = "http://www.ibiblio.org/xml/examples/shakespeare/macbeth.xml"
IGNORE_SPEAKERS = %w(ALL)
def initialize(parser)
@parser = parser
@speaker_line_counts = analyze_speaker_line_counts
end
def analyze_speaker_line_counts
speaker_line_counts = Hash.new(0)
speakers = parser.parse(query: '//SPEAKER')
speakers.map do |speaker|
unless IGNORE_SPEAKERS.include? speaker.text
speaker_line_counts[speaker.text] += parser.parse(
node: speaker, query: '../LINE').count
end
end
speaker_line_counts
end
private
attr_reader :parser
end
if __FILE__ == 0ドル
analyzer = MacbethAnalyzer.new(XmlParser.new(MACBETH_URL))
Printer.print_hash_val_capitalized_key(
hash: analyzer.speaker_line_counts, filter: 'ALL')
end
Now MacbethAnalyzer
doesn't depend on a lower-level implementation; we use duck typing to make things flexible, removing the dependency and resulting in much more loosely coupled code.