Strategy patterns for Ruby and JavaScript

Source: Internet
Author: User


From the official


The policy pattern defines a series of algorithms, encapsulates each algorithm, and allows them to be replaced with each other. The policy pattern makes the algorithm independent of the customers who use it.


Structure diagram




Simple implementations in Ruby (code from Ruby design mode)
# According to the duck model, there is no policy object to inherit a base class that provides a uniform interface
#策略1
Class HTMLFormatter
  Def output_report title, text
    Puts ‘<html>‘
    Puts ‘ <head> ‘
    Puts ‘ <title>‘ + title + ‘</title>‘
    Puts ‘ </head> ‘
    Puts ‘ <body>‘
    Text.each do |line|
      Puts "<p>#{line}</p>"
    End
    Puts ‘ </body> ‘
    Puts ‘</html>‘
  End
End

#策略2
Class PlainTextFormatter
  Def output_report title, text
    Puts ‘******** ‘ + title + ‘ ********’
    Text.each do |line|
      Puts line
    End
  End
End

# The reason why this strategy is used is because Reporter may print text into text in different formats, if needed in the future
#Support xml then only need to add a class that supports the output_report interface.
Class Reporter
  Attr_reader :title, :text
  Attr_accessor :formater

  Def initialize formater
    @title = ‘My Report’
    @text = [‘This is my report‘, ‘Please see the report’, ‘It is ok’]
    @formater = formater
  End

  # Policy objects have a common interface
  Def output_report
    @formater.output_report @title, @text
  End
End

# Environment object calls different strategies
Reporter.new(HTMLFormatter.new).output_report
Reporter.new(PlainTextFormatter.new).output_report 


So when can the strategy model be used?
Let's start with an example, in general, if we want to do data validation, many times are based on the Swith statement to judge, but this brings a few problems, first of all, if we increase the demand, we also need to modify this code to add logic, and in the unit test is more complex, The code is as follows:


# At the earliest time, I almost used this method to do the data validation of the form.
Validator = {
             Validate: function (value, type) {
                 Switch (type) {
                     Case ‘isNonEmpty ‘:
                         {
                             Return true; // NonEmpty verification result
                         }
                     Case ‘isNumber ‘:
                         {
                             Return true; // Number verification result
                             Break;
                         }
                     Case ‘isAlphaNum ‘:
                         {
                             Return true; // AlphaNum verification result
                         }
                     Default:
                         {
                             Return true;
                         }
                 }
             }
         };
         // test
         Alert(validator.validate("123", "isNonEmpty")); 


OK, with the strategy model to change, first analysis of validator is a strategic environment, different authentication is a policy object, we need to do is to allow different policy objects to support the unified interface
The refactoring code is as follows:


Var validator = {

    Types: {},

    Messages: [],

    Config: {},

    Validate: function (data) {

        Var i, msg, type, checker, result_ok;

        This.messages = [];

        For (i in data) {
            If (data.hasOwnProperty(i)) {

                Type = this.config[i]; // Query whether there is an existing validation rule based on the key

                Checker = this.types[type]; // Get the validation class for the validation rule

                If (!type) {
                    Continue; // If the validation rule does not exist, it will not be processed
                }
                If (!checker) { // throw an exception if the validation rule class does not exist
                    Throw {
                        Name: "ValidationError",
                        Message: "No handler to validate type " + type
                    };
                }
                # Start performing different strategies on demand
                Result_ok = checker.validate(data[i]); // Verify using the single validation class found
                If (!result_ok) {
                    Msg = "Invalid value for *" + i + "*, " + checker.instructions;
                    This.messages.push(msg);
                }
            }
        }
        Return this.hasErrors();
    },

    hasErrors: function () {
        Return this.messages.length !== 0;
    }
};

// Verify that the given value is not empty
validator.types.isNonEmpty = {
    Validate: function (value) {
        Return value !== "";
    },
    Instructions: "The value passed in cannot be empty"
};

// Verify that the given value is a number
Validator.types.isNumber = {
    Validate: function (value) {
        Return !isNaN(value);
    },
    Instructions: "The value passed in can only be a legal number, for example: 1, 3.14 or 2010"
};

// Verify that the given value is just a letter or number
Validator.types.isAlphaNum = {
    Validate: function (value) {
        Return !/[^a-z0-9]/i.test(value);
    },
    Instructions: "The value passed in can only protect letters and numbers, not special characters"
};

Var data = {
    First_name: "Tom",
    Last_name: "Xu",
    Age: "unknown",
    Username: "TomXu"
};

Validator.config = {
    First_name: ‘isNonEmpty‘,
    Age: ‘isNumber‘,
    Username: ‘isAlphaNum‘
};

Validator.validate(data);

If (validator.hasErrors()) {
    Console.log(validator.messages.join("\n"));
} 


Early time to see this code I just want to say fuck, obviously very simple things, not to engage in such a complex is necessary?
Of course, assuming the project is simple, use the code before refactoring OK, and here's just an example.



So how does the same need to be achieved with Ruby?
Here's the code: (I'm writing Ruby with JavaScript in mind, I don't know if there's a problem with reading)


 
# coding: utf-8

# Strategy 1
Class IsNonEmpty
  Def self.check(data)
    Data.nil?
  End

  Def self.notice
    "The value passed in cannot be empty \n"
  End
End

# Strategy 2
Class IsAlphaNum
  Def self.check(data)
    Data =~ /[^a-z0-9]/
  End

  Def self.notice
    "Incoming values can only protect letters and numbers, cannot contain special characters \n"
  End
End

# surroundings
Class Validate
  Attr_reader :msg

  Def initialize
    # @types = []
    @msg = ‘‘
    # @config = {}
  End

  # This place is not written according to the logic of javascript, if you need different instances to support different verification,
  # Can add policy objects to @types
 @config Same as
  # def add_types(type)
  # @types << type
  # end

  Def check(hash_data)
    Hash_data.each_pair do |key, val|
      @msg << "#{key}errors #{val[:type].notice}" if val[:type].check(val[:data])
    End
  End

  Def errors
    !@msg.nil?
  End
End

Validate = Validate.new

Hash_data = {
    First: {type: IsNonEmpty, data: 1324},
    Second: {type: IsNonEmpty, data: nil},
    Third: {type: IsAlphaNum, data: ‘123angel‘},
    Forth: {type: IsAlphaNum, data: ‘123sf@/!’}
}

Validate.check(hash_data)
If validate.errors
  Puts validate.msg
End


Finally: This is intended to summarize the differences between Ruby and JavaScript shared interface, but the ability is limited, can only be understood and can not be expressed
Or maybe it's for the lack of understanding of the key points.



Strategy patterns for Ruby and JavaScript


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.