ruby和javascript的策略模式

來源:互聯網
上載者:User

標籤:

來自官方

策略模式定義了一系列的演算法,並將每一個演算法封裝起來,而且使它們還可以相互替換。策略模式讓演算法獨立於使用它的客戶而獨立變化。

結構圖

ruby中的簡單實現(代碼來自《ruby設計模式》)
# 根據鴨子模型, 沒有讓策略對象繼承一個提供統一介面的基類# 策略1class 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>‘  endend# 策略2class PlainTextFormatter  def output_report title, text    puts ‘******** ‘ + title + ‘ ********‘    text.each do |line|      puts line    end  endend# 這邊之所以用策略模式來做,是因為Reporter有可能會將text列印成不同格式的文本,如果將來需要# 支援xml那麼只需要增加一個支援output_report介面的類就可以了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  # 策略對象具有共同的介面  def output_report    @formater.output_report @title, @text  endend# 環境對象調用不同的策略Reporter.new(HTMLFormatter.new).output_reportReporter.new(PlainTextFormatter.new).output_report

那麼策略模式到底可以在什麼時候用呢?
我們先來一個例子,一般情況下,如果我們要做資料合法性驗證,很多時候都是按照swith語句來判斷,但是這就帶來幾個問題,首先如果增加需求的話,我們還要再次修改這段代碼以增加邏輯,而且在進行單元測試的時候也會越來越複雜,代碼如下:

# 在最早的時候我差不多就是用這樣的方式去做表單的資料驗證的validator = {            validate: function (value, type) {                switch (type) {                    case ‘isNonEmpty ‘:                        {                            return true; // NonEmpty 驗證結果                        }                    case ‘isNumber ‘:                        {                            return true; // Number 驗證結果                            break;                        }                    case ‘isAlphaNum ‘:                        {                            return true; // AlphaNum 驗證結果                        }                    default:                        {                            return true;                        }                }            }        };        //  測試        alert(validator.validate("123", "isNonEmpty"));

ok, 用策略模式去改造一下, 首先分析一下validator是一個策略環境,不同的驗證就是一個策略對象,我們需要做的就是讓不同的策略對象支援統一的介面
重構代碼如下:

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];  // 根據key查詢是否有存在的驗證規則                checker = this.types[type]; // 擷取驗證規則的驗證類                if (!type) {                    continue; // 如果驗證規則不存在,則不處理                }                if (!checker) { // 如果驗證規則類不存在,拋出異常                    throw {                        name: "ValidationError",                        message: "No handler to validate type " + type                    };                }                # 開始執行按需執行不同的策略                result_ok = checker.validate(data[i]); // 使用查到到的單個驗證類進行驗證                if (!result_ok) {                    msg = "Invalid value for *" + i + "*, " + checker.instructions;                    this.messages.push(msg);                }            }        }        return this.hasErrors();    },    hasErrors: function () {        return this.messages.length !== 0;    }};// 驗證給定的值是否不為空白validator.types.isNonEmpty = {    validate: function (value) {        return value !== "";    },    instructions: "傳入的值不可為空"};// 驗證給定的值是否是數字validator.types.isNumber = {    validate: function (value) {        return !isNaN(value);    },    instructions: "傳入的值只能是合法的數字,例如:1, 3.14 or 2010"};// 驗證給定的值是否只是字母或數字validator.types.isAlphaNum = {    validate: function (value) {        return !/[^a-z0-9]/i.test(value);    },    instructions: "傳入的值只能保護字母和數字,不能包含特殊字元"};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"));}

早期的時候看到這樣的代碼我只想說fuck, 明明很簡單的東西,非搞的這麼複雜有必要嗎?
當然, 假設項目很簡單,用重構前的代碼OK, 而且這裡也只是去舉個例子

那麼同樣的需求用ruby如何?呢?
代碼如下:(這裡我完全是用javascript的思維來寫ruby了, 不知道閱讀性有沒有問題)

# coding: utf-8# 策略1class IsNonEmpty  def self.check(data)    data.nil?  end  def self.notice    "傳入的值不可為空\n"  endend# 策略2class IsAlphaNum  def self.check(data)    data =~ /[^a-z0-9]/  end  def self.notice    "傳入的值只能保護字母和數字,不能包含特殊字元\n"  endend# 環境class Validate  attr_reader :msg  def initialize    # @types = []    @msg = ‘‘    # @config = {}  end  # 這個地方沒有再按照javascript的邏輯去寫,這邊如果需要不同的執行個體支援不同的驗證的話,  # 可以將策略對象添加到@types中  # @config 同理  # 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?  endendvalidate = Validate.newhash_data = {    first: {type: IsNonEmpty, data: 1324},    second: {type: IsNonEmpty, data: nil},    third: {type: IsAlphaNum, data: ‘123angel‘},    forth: {type: IsAlphaNum, data: ‘[email protected]/!‘}}validate.check(hash_data)if validate.errors  puts validate.msgend

最後: 本打算總結出ruby和javascript共用介面的不同, 奈何能力有限,只能意會出來卻不能言傳出來
也可能是為沒有理解出其中的關鍵點

ruby和javascript的策略模式

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.