Reprinted please indicate the source: http://blog.csdn.net/guolin_blog/article/details/8742681
This is a copy version of Java Design Pattern dialysis, which is specially provided for Ruby lovers. If you are not familiar with Ruby syntax, please refer:
Java Design Pattern Analysis-Template Method)
Today, you have started programming as usual.
The project manager tells you that you want to add a new function on the server today. You want to write a method to process the book object and wrap all the fields of the book object in XML format, in this way, you can easily interact with the client. In addition, logs must be printed before and after the packaging starts to facilitate debugging and problem locating.
No problem! You think this feature is just a piece of cake, and you are very confident to start writing code.
The code of the book object is as follows:
class Bookattr_accessor :book_name, :pages, :price, :author, :isbnend
Then write a class specifically used to wrap the book object into XML format:
class Formatterdef format_book(book)puts "format begins"result = "<book_name>#{book.book_name}</book_name>\n"result += "<pages>#{book.pages}</pages>\n"result += "<price>#{book.price}</price>\n"result += "<author>#{book.author}</author>\n"result += "<isbn>#{book.isbn}</isbn>\n"puts "format finished"resultendend
The call code is as follows:
book = Book.newbook.book_name = "Programming Ruby"book.pages = 830book.price = 45book.author = "Dave Thomas"book.isbn = "9787121038150"formatter = Formatter.newresult = formatter.format_book(book)puts result
After you write it, you can't wait to start running, and the running results fully meet your expectations.
After reading this, the project manager is very satisfied with you. The efficiency is very high! You are also very proud.
However, two days later, the project manager found you again. He said that he did not consider the clients that needed to interact, including mobile phone devices, and mobile phone devices both ate traffic, it is too traffic-consuming to transmit data in XML format. It is recommended that the data be transmitted in JSON format. However, the previous XML format should also be retained. It is best to specify the format used by the client.
You are a little unhappy and have an underestimating mind. Why didn't you think about it at first? Now you have to change the legacy code. After all, the other party is the leader, and you still have to obey the command, so you begin to modify the formatter class:
class Formatterdef format_book(book, format)puts "format begins"result = ""if format == :xmlresult += "<book_name>#{book.book_name}</book_name>\n"result += "<pages>#{book.pages}</pages>\n"result += "<price>#{book.price}</price>\n"result += "<author>#{book.author}</author>\n"result += "<isbn>#{book.isbn}</isbn>\n"elsif format == :jsonresult += "{\n"result += "\"book_name\" : \"#{book.book_name}\",\n"result += "\"pages\" : \"#{book.pages}\",\n"result += "\"price\" : \"#{book.price}\",\n"result += "\"author\" : \"#{book.author}\",\n"result += "\"isbn\" : \"#{book.isbn}\",\n"result += '}'endputs "format finished"resultendend
The call code is as follows:
book = Book.newbook.book_name = "Programming Ruby"book.pages = 830book.price = 45book.author = "Dave Thomas"book.isbn = "9787121038150"formatter = Formatter.newresult = formatter.format_book(book, :xml)puts resultresult = formatter.format_book(book, :json)puts result
Run the program again and get the following results.
After seeing the running result, the Project Manager happily said, "Great, this is exactly what I want !"
However, you are not so happy this time. You think the code is a bit messy. The logic in XML format is mixed with the logic in JSON format, which is very difficult to read, in addition, it will be very difficult to extend functions in the future. Fortunately, the transmission format is generally XML and JSON, and there should be no extensions, so you can comfort yourself.
However, fantasies will always be broken by reality. "I recently heard that a yaml format is fun..." said the project manager. At this time, you have an impulse to beat people !!!
Most of the time, the code written in the company is messy and of poor quality. A major reason is that the demand changes. We constantly add various subsequent additions based on the original code. Our code becomes unsightly under the IF statement added in a row. Of course, as a programmer, we do not have much right to speak about such things as demand, and we can't do anything about it. However, we can design the program architecture as much as possible, so that the code we write is more scalable, so that we can respond to various changes in requirements.
Below you will use the template method in 23 design patterns to improve the above program.
First, define a special subclass to process the specific logic of each transmission format, so that the logic of different transmission formats can be separated from one method, which is obviously easy to read and understand.
The definition class xmlformatter inherits from formatter, which includes the specific logic for processing the XML format:
class XMLFormatter < Formatterdef formating(book)result = "<book_name>#{book.book_name}</book_name>\n"result += "<pages>#{book.pages}</pages>\n"result += "<price>#{book.price}</price>\n"result += "<author>#{book.author}</author>\n"result += "<isbn>#{book.isbn}</isbn>\n"endend
The definition class jsonformatter inherits from the formatter, which includes the specific logic for processing the JSON format:
class JSONFormatter < Formatterdef formating(book)result = "{\n"result += "\"book_name\" : \"#{book.book_name}\",\n"result += "\"pages\" : \"#{book.pages}\",\n"result += "\"price\" : \"#{book.price}\",\n"result += "\"author\" : \"#{book.author}\",\n"result += "\"isbn\" : \"#{book.isbn}\",\n"result += '}'endend
Modify the code in formatter as follows:
class Formatterdef format_book(book)before_formatresult = formating(book)after_formatresultenddef before_formatputs "format begins"enddef formating(book)raise "You should override this method in subclass."enddef after_formatputs "format finished"endend
You will find that the format_book method has only four steps. The first step is to call before_format to print the logs before the format conversion. The second step is to call formating to process the specific conversion logic. However, The formating method only has an exception in raise, because the specific conversion logic should be processed by sub-classes, if the formating method of the parent class is used, an exception occurs. Step 3 call after_format to print the log after the format conversion. Step 4: return the result.
The call code is as follows:
book = Book.newbook.book_name = "Programming Ruby"book.pages = 830book.price = 45book.author = "Dave Thomas"book.isbn = "9787121038150"xmlFormatter = XMLFormatter.newresult = xmlFormatter.format_book(book)puts resultjsonFormatter = JSONFormatter.newresult = jsonFormatter.format_book(book)puts result
After running, you will find that the running results are exactly the same as those of the code before modification. However, after the template method is used, the code readability is greatly improved, because the code for processing format conversion is put into their respective classes, rather than all being inserted into one method. In addition, the scalability has also been greatly improved. For example, you are interested in the yaml format described by the Project Manager.
The definition class yamlformatter inherits from the formatter, which includes the specific logic for processing the yaml format:
class YAMLFormatter < Formatterdef formating(book)result = "book_name: #{book.book_name}\n"result += "pages: #{book.pages}\n"result += "price: #{book.price}\n"result += "author: #{book.author}\n"result += "isbn: #{book.isbn}\n"endend
To call the code, you only need to add:
yamlFormatter = YAMLFormatter.newresult = yamlFormatter.format_book(book)puts result
Well, the annoying yaml format is supported in this way. You only need to decide whether to instantiate xmlformatter, jsonformatter or yamlformatter during the call, and then convert the format according to the corresponding specifications. The overall code is very organized and looks comfortable. At this time, you will easily ridicule the Project Manager, do you still need to support the format?
Template Method: defines the skeleton of an algorithm in an operation, and delays some steps to the subclass, the template method allows the subclass to redefine certain steps of an algorithm without changing the structure of an algorithm.