Analysis of Ruby design patterns-strategy)

Source: Internet
Author: User

Reprinted please indicate the source: http://blog.csdn.net/guolin_blog/article/details/8986299

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:

Analysis of Java design patterns -- Strategy) 

Today, your leader is eager to find you. I hope you can help him. He is in a hurry to go to the meeting. What can I do? You are curious.

He told you that there is a user information table in the database of your project, which stores user data. Now you need to perform a selective query of user information. He said that it will pass you an array containing many user names. You need to check the corresponding data based on these user names.

This function is very simple. You readily agreed. Because your project uses the MySQL database, you quickly wrote the following code:

Require 'mysql' class queryutildef find_user_info usernames @ DB = MySQL. real_connect ("localhost", "root", "123456", "test", 3306); SQL = "select * From user_info where" usernames. each do | user | SQL <"username = '" SQL <usersql <"' or" endputs sqlresult = @ dB. query (SQL); result. each_hash do | row | # processing the data read from the Database End # The data to be read should be assembled into an object to return, here the ensure@db.closeendend is omitted

The SQL statement is assembled based on the input username array and then the corresponding row is searched in the database. For debugging, you can print the assembled SQL statements.

Then, you write the following code to test this method:

qUtil = QueryUtil.newqUtil.find_user_info ["Tom", "Jim", "Anna"]

Run the test code and you will find that the program has an error. So you immediately checked the printed SQL statement and found the problem.

select * from user_info where username = 'Tom' or username = 'Jim' or username = 'Anna' or 

The assembled SQL statement adds an OR keyword at the end! Because the for loop should not be followed by or when it is executed to the last piece of data, but the code is too stupid to add the or keyword to the last piece of data, resulting in an SQL statement syntax error.

What should I do?

Yes! You came up with a solution. After the SQL statement is assembled, it will not be enough to capture the last or previous position. So you can change the code to the following:

Require 'mysql' class queryutildef find_user_info usernames @ DB = MySQL. real_connect ("localhost", "root", "123456", "test", 3306); SQL = "select * From user_info where" usernames. each do | user | SQL <"username = '" SQL <usersql <"' or" endsql = SQL [0 .. -"or ". length] puts sqlresult = @ dB. query (SQL); result. each_hash do | row | # processing the data read from the Database End # The data to be read should be assembled into an object to return, here the ensure@db.closeendend is omitted

Use the substring truncation method of string to obtain only the last or before, and then run the test code. Everything is normal. The printed SQL statement is as follows:

select * from user_info where username = 'Tom' or username = 'Jim' or username = 'Anna'

All right, finished! You are confident.

After the opening of your leader, I came to see your results. In general, he is quite satisfied, but he always feels a bit wrong about the SQL statement assembly algorithm you use, but he can't tell where it is. So he told you another algorithm used to assemble SQL statements, so that you can add them to the Code. However, do not delete the previous algorithms. Keep them first, then he ran away very busy. So you added the algorithm he just taught you. The Code is as follows:

Require 'mysql' class queryutildef find_user_info (usernames, Strategy) @ DB = MySQL. real_connect ("localhost", "root", "123456", "test", 3306); SQL = "select * From user_info where" If strategy = 1usernames. each do | user | SQL <"username = '" SQL <usersql <"' or" endsql = SQL [0 .. -"or ". length] elsif strategy = 2need_or = falseusernames. each do | user | SQL <"or" If need_orsql <"username = '" SQL <usersql <"'" need_or = trueendendputs sqlresult = @ dB. query (SQL); result. each_hash do | row | # processing the data read from the Database End # The data to be read should be assembled into an object to return, here the ensure@db.closeendend is omitted

As you can see, leader teaches you how to assemble an algorithm and uses a Boolean variable to control whether to add the or keyword. The first time you execute a for loop, the Boolean value is false, so no or is added, and the Boolean value is assigned to true at the end of the loop. In this way, an OR keyword is added to the header each time in the loop. Because the or method is added to the header, so you don't have to worry about one more or at the end of the SQL statement. Then, to retain both algorithms, you add a parameter to the find_user_info method. If the value of strategy is 1, the first algorithm is used. If the value of strategy is 2, the second algorithm is used.

In this way, the test code also needs to be changed to the following method:

qUtil = QueryUtil.newqUtil.find_user_info(["Tom", "Jim", "Anna"], 2)

Here, you use the parameter to specify the second algorithm to assemble SQL statements. The printed results are exactly the same as those of the first algorithm.
You immediately dragged your leader from your busy schedule and asked him to test your current achievements. However, he is still picky.

"If you write this way, the logic of the find_user_info method is too complicated, so it is not conducive to reading and expansion in the future. If I want to add the third and fourth algorithms, can this method be viewed?" Your leader instructs you to use the rule mode to solve this problem. The core idea of the rule mode isExtract the algorithm into an independent object..

To help you, he started to teach you how to use the policy mode for optimization regardless of his busy schedule.

First, define a parent class. The parent class contains a get_ SQL method. This method simply throws an exception:

class Strategydef get_sql usernamesraise "You should override this method in subclass."endend

Then we define that both child classes inherit the parent classes and add the two algorithms for assembling SQL statements to the two child classes respectively:

class Strategy1def get_sql usernamessql = "select * from user_info where "usernames.each do |user|sql << "username = '"sql << usersql << "' or "endsql = sql[0 .. -" or ".length]endend
class Strategy2def get_sql usernamessql = "select * from user_info where "need_or = falseusernames.each do |user|sql << " or " if need_orsql << "username = '"sql << usersql << "'"need_or = trueendendend

Then, call the get_ SQL method of strategy in the find_user_info method of queryutil to obtain the assembled SQL statement. The Code is as follows:

Require 'mysql' class queryutildef find_user_info (usernames, Strategy) @ DB = MySQL. real_connect ("localhost", "root", "123456", "test", 3306); SQL = strategy. get_ SQL (usernames) puts sqlresult = @ dB. query (SQL); result. each_hash do | row | # processing the data read from the Database End # The data to be read should be assembled into an object to return, here the ensure@db.closeendend is omitted

Finally, when the test code calls the find_user_info method, it only needs to explicitly specify the policy object to be used:

qUtil = QueryUtil.newqUtil.find_user_info(["Tom", "Jim", "Anna"], Strategy1.new)qUtil.find_user_info(["Jac", "Joe", "Rose"], Strategy2.new)

The printed SQL statement is as follows:

select * from user_info where username = 'Tom' or username = 'Jim' or username = 'Anna'select * from user_info where username = 'Jac' or username = 'Joe' or username = 'Rose'

After the policy mode is modified, the Code's readability and scalability are greatly improved. Even if you need to add new algorithms in the future, you can easily get it!

Policy: it defines the algorithm family and encapsulates them separately. Let them replace each other. This pattern changes the algorithm and does not affect the customers who use the algorithm.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.