你好,我是富士大顆 Aiko
今天來談談 什麼是 DRY 以及有哪些方式可以進行
一次且僅一次(Once and only once) 又稱為 DRY(Don't Repeat Yourself)是一個軟體開發中非常重要的概念,也是敏捷開發 Agile 的核心,特別是在 Ruby on Rails 等框架中。DRY 原則的主要目的是減少重複的程式碼,以提高軟體的可維護性、可讀性和可重用性。這裡有幾種常用的方法來實踐 DRY:
像 Ruby 這種動態語言(Dynamic Language)中,方法和函數的重用性非常強,能有效地實踐 DRY 原則,將重複的程式碼片段封裝成方法或函數,然後在其他地方呼叫這個方法。所謂的動態語言有幾個強項:
--1.Runtime Modifications 執行時動態地改變物件的結構,更多的彈性使用可重用的程式碼。
--2.Type Inference 不用特別聲明變數的類型,執行時自動推斷,這樣就更容易寫出可重用的函數或方法。
封裝(Encapsulation)是一個物件導向程式設計(Object-Oriented Programming, OOP)的基本概念,用於將資料(屬性)和與之相關的行為(方法)包裝在單一的單位或物件中,在 Ruby 也就是 block(從 def 到 end 中間的那些)。在實踐 DRY 原則的過程中,封裝通常用於將重複的程式碼片段組織成單一的、可重用的方法或函數。這樣,當需要修改這段代碼時,只需要在一個地方進行修改,從而提高了可維護性和可讀性。
def calculate_area1
3.14 * 5 * 5
end
def calculate_area2
3.14 * 10 * 10
end
同樣的邏輯算法重複了,可以改成:
def calculate_area(n)
3.14 * n * n
end
通過繼承,子類可以重用父類中的方法和屬性。
class Father
def make_money
puts "I like money"
end
end
class Son < Father
end
son.make_money
#"I like money"
在 Ruby 裡,模組(Modules)主要是用來封裝(Encapsulation)相關的方法、常量(Constant,全大寫,初始化後就不建議改變,rails 會提出警告)等,以便能夠重用這些程式碼片段。模組不能被實體化(Instantiate),也就是不能建立一個模組的實體。
module MyModule
def a_method
"doing sth"
end
end
instance = MyModule.new
#這樣會噴錯:`NoMethodError`
namespace:
puts MyModule::a_method
#這種情況下會出錯,因為 a_method 是一個實例方法,不能這樣直接調用
直接使用模組名稱來調用模組方法:
module MyModule
def self.a_method
"doing sth"
end
end
# 使用模組名稱來使用
puts MyModule.a_method
#"doing sth"
類別(非模組)被實體化:
module MyModule
def a_method
"doing sth"
end
end
class MyClass
include MyModule
end
instance = MyClass.new
puts instance.a_method
#"doing sth"
但可以把模組「混入(Mix in)」到類別(Classes)或其他模組中。
混入是一種在不使用繼承(Inheritance)的情況下,將一個模組的功能加入到一個或多個類別的方法。這是 Ruby 中實現多重繼承(Multiple Inheritance)的一種方式。可以使用 include
和 extend
這兩個關鍵字來進行混入(Mixins)
-include
會將模組(Module)中的方法加入到類別(Class)的實體方法中。也就是需要實體化(Instantiate)該類別的物件才能使用這些方法。
module Greetable
def greet
puts "Hello, I'm a module method."
end
end
class Person
include Greetable
end
p = Person.new
p.greet # 輸出 "Hello, I'm a module method."
-extend
將模組中的方法加入到類別的類別方法中,或者將模組中的方法加入到單個物件的單件方法(Singleton Methods)中。
module ClassMethods
def class_greet
puts "Hello, I'm a class method."
end
end
class Person
extend ClassMethods
end
Person.class_greet # 輸出 "Hello, I'm a class method."
差別 | include | extend |
---|---|---|
作用域 (scope) | 把模組的方法作為實例方法加入類別中 | 把模組的方法作為類別方法加入 |
調用方式(Invocation) | 需要通過類別的實體來調用 | 直接透過類別來使用 |
用途(Usage) | 當你希望模組中的方法能在多個類的實例中重用 | 把一個模組的方法加入到單個物件中,或者作為類別方法加入到整個類中。 |
在 Rails 中,ActiveSupport::Concern
模組提供了一個更加簡化和標準化的方式來創建和使用混入。使用 ActiveSupport::Concern
,可以更容易地管理依賴和程式碼組織。
# app/models/concerns/nameable.rb
module Nameable
extend ActiveSupport::Concern
included do
validates :name, presence: true
end
end
這裡定義了一個名為 Nameable
的模組。這個模組使用 ActiveSupport::Concern
,並在被其他類別引用(Include)後,會自動執行 included
塊內的程式碼。
# app/models/user.rb
class User < ApplicationRecord
include Nameable
end
#少寫validates :name, presence: true
在這裡,User
類別引用了 Nameable
模組。這意味著 User
類會繼承 Nameable
模組中定義的所有方法和功能。在這個例子中,User
類會自動獲得一個名字(name)的驗證,要求名字必須存在(presence: true)。
這種方式允許你將共享的邏輯(例如,名字的驗證)抽取出來,並封裝在一個模組中,然後再混入到需要這些功能的類別中。當你需要更改某個邏輯或功能時,只需在一個地方進行更改,而不是在多個地方進行更改,這大大減少了出錯的機會和減輕了維護的負擔,這樣就達到了 DRY(Don't Repeat Yourself)的目的。
在 Rails 控制器或模型中,使用像 before_action
這樣的過濾器或回呼,以在執行某些動作之前或之後運行特定的程式碼。能讓我們在不同的動作(Actions)之間共享邏輯,這也是 DRY 的一種實現。
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :authenticate_user!
end
# app/controllers/users_controller.rb
class UsersController < ApplicationController
# authentication will run first due to inheritance
end
為了增加安全性,對重複出現的參數過濾可以抽取出一個方法。能讓我們在一個地方定義參數過濾邏輯,然後在多個地方重複使用。
# app/controllers/users_controller.rb
class UsersController < ApplicationController
private
def user_params
params.require(:user).permit(:username, :email, :password)
end
end
在視圖中,如果有重複的 HTML 結構,可以使用部分視圖來重用這些結構。這在前端開發中是一個常見的 DRY 實踐,尤其是在使用像 ERB 這種模板語言時。
重複使用的畫面:
<!-- app/views/shared/_header.html.erb -->
<header>
<!-- header content -->
</header>
其他畫面想用:
<!-- app/views/layouts/application.html.erb -->
<%= render 'shared/header' %>
這些方法讓 DRY 原則可以都有效地應用在 Ruby on Rails 的開發中,
使用這些 DRY 的實踐方式或概念,可以讓你的 Ruby、SQL 或 JavaScript 程式碼更加乾淨、有組織,也更易於團隊合作。
無論你是專注於後端還是前端,或者全端工程師,掌握和運用 DRY 原則都是非常重要的。
一起super DRY 起來~~