---
# System prepended metadata

title: 設計模式（單一職責的類別）

---

# 設計模式（單一職責的類別）

## 程式碼的組織
* 修改不會產生意想不到的副作用（所有橡膠鴨子一起飛）
* 輕微的需求變化也只需要輕微的程式碼修改（不要為每個鴨子行為複寫）
* 既有的程式碼易於重複使用
* 最簡單的修改方式是增加其自身也易於修改的程式碼

## 程式碼的特點
* 透明性：程式碼的修改結果應該顯而易見，無論是在其自身修改處或是在遠處依賴於它的程式碼
* 合理性：任何修改所產生的成本都應該與修改所帶來的效益成正比
* 可用性：既有得程式碼在有所不同以及非預期的上下文中仍然保持可用性
* 典範性：程式碼本身應該鼓勵那些為延續這些特點而對它進行的修改

---
想利用程式碼計算ratio
```ruby=
chainring = 52 #齒輪牙的數量
cog = 11
ratio = chainring / cog.to_f

chainring = 30 #齒輪牙的數量
cog = 27
ratio = chainring / cog.to_f
```
重複程式碼：建立類別
```ruby=
class Gear
    attr_reader :chainring, :cog
    def initialize(chainring, cog)
        @chainring = chainring
        @cog = cog
    end
    
    def ratio
        chainring / cog.to_f
    end    
end


#只需要給予兩個數值，就可以得到結果
Gear.new(52, 11).ratio 
Gear.new(30, 27).ratio
```
需求變更：車輪尺寸更動
```ruby=
class Gear
    attr_reader :chainring, :cog, :rim, :tire
    def initialize(chainring, cog, rim, tire)
        @chainring = chainring
        @cog = cog
        @rim = rim
        @tire = tire
    end
    
    def ratio
        chainring / cog.to_f
    end    
    
    def gear_inches
        ratio * (rim + (tire * 2))
    end
end

#需要輸入更多數值，才能得到結果
Gear.new(52, 11, 26, 1.5).gear_inches

#噴錯給你看
Gear.new(52, 11).ratio
```
所以齒輪有需要理解輪胎嗎？
應用單一職責實現類別運作（內聚：類別內容都與中心目標相關聯）
* 別誤會了，單一職責並非侷限工作，而是要讓你的工作郖跟中心目標有所關聯）

1. 隱藏實例變數
```ruby=
attr_reader
#https://www.rubyguides.com/2018/11/attr_accessor/
```
2. 隱藏資料結構
```ruby=
class ObscuringReferences
    attr_reader :data
    def initialize(data)
        @data = data
    end
    
    def diameters
        data.collect {|cell|
        cell[0] + (cell[1] * 1)}
    end
end

#必須知道data"是什麼"
```

## 實行單一職責
```ruby=
class Gear
    attr_reader :chainring, :cog, :wheel
    def initialize(chainring, cog, wheel = nil)
        @chainring = chainring
        @cog = cog
        @wheel = wheel
    end
    
    def ratio
        chainring / cog.to_f
    end
    
    def gear_inches
        ratio * wheel.diameter
    end
    
class Wheel
    attr_reader :rim, :tire
    def initialize(rim, tire)
        @rim = rim
        @tire = tire
    end
    
    def diameter
        rim + (tire * 2)
    end
    
    def circumference
        diameter * Math::PI
    end
end
    
@wheel = Wheel.new(26, 1.5)

Gear.nwe(52, 11, @wheel).gear_inches
    
Gear.nwe(52, 11).ratio
```