# 클래스

### **단일 책임 원칙(SRP) 지키기**

* 하나의 클래스는 하나의 책임만 갖도록 설계한다.
* 클래스도 작아야 가독성과 유지보수 측면에 이점이 있다.

```swift
// as-is
class Store {                 // Store 클래스가 많은 역할을 혼자 수행한다.
    func cummunicateUser() { }
    func manageProducts() { }
    func manageMoney() { }
}
```

```swift
// to-be
class CounterManager {
    func communicateUser() { }
}

class ProductManager {
    func manageProducts() { }
}

class Owner {
    func manageMoney() { }
}

class Store {
    let counterManager: CounterManager
    let productManager: ProductManater
    let owner: Owner

    func sellProduct() {
        counterManager.communicateUser()
        // code
    }
    // code...
}
```

### **응집도를 높이자.**

* 응집도는 클래스의 변수와 메서드가 얼마나 유기적으로 엮여있는지를 나타내는 지표이다.
  * 응집도가 높을수록 클래스의 메서드는 인스턴스 변수를 많이 사용한다.
  * 응집도가 낮을수록 클래스의 메서드는 인ㅅ턴스 변수를 적게 사용하거나 사용하지 않는다.

```swift
// as-is

class LowCohension {
    var a: Int
    var b: Int
    var c: Int

    func processA() {
        print(self.a)
    }

    func processB() {
        print(self.b)
    }

    func processC() {
        print(self.c)
    }
}
```

```swift
// to-be
class HighCohension {
    var abc: ABC

    func processA() {
        print(self.abc.processA())
    }

    func procesB() {
        print(self.abc.processB())

    func procesC() {
        print(self.abc.processC())
}
```

```swift
// 실제 코드, element인스턴스가 3개의 메서드에서 모두 사용되고 있다.
class Stack { 
    var elements = [Int]()

    func size() -> Int {
        return elements.count
    }

    func push(_ element: Int) {
        elements.append(element)
    }

    func pop() -> Int? {
        guard !elements.isEmpty else { return nil }
        return elements.removeLast()
    }
}
```

***

### **변경하기 쉽게 만들자 (open closed)**

* 다형성과 연결되는 부분이다.
* 새 기능을 수정하거나 기존 기능을 변경할 때, 코드의 변경으 최소화하는 것이 중요하다.
* 일반적으로 클래스(객체)는 구현과 추상으로 나뉜다.
  * 구현(Concrete) : 실제 동작하는 구체적 코드
  * 추상 (Abstract) : 구체적인 기능을 개념화한 코드
* 변경하기 쉽게 설계하기 위해서, 추상화를 통해 구체 클래스에 의존하지 않고, 추상 클래스에 의존하도록 코드를 작성하는 것이 중요하다.

  ```swift
  // as-is
  class Developer {
      func coding() {
          print("코딩을 합니다")
      }
  }

  class Designer {
      func design() {
          print("디자인을 합니다")
      }
  }

  class Analyst {
      func analyze() {
          print("분석을 합니다")
      }
  }

  class Company {
      var employees = [Employee]

      func makeWokr() {
          for employee in employess {
              switch employee {
              case .developer:
                  employee.coding()
              case .designer:
                  employee.disign()
              case .analyst:
                  employee.analyze()
              }
          }
      }
  }
  ```

  ```swift
  // to-be
  protocol Employee {
      func work()
  }

  class Company {
      var employees = [Employee]

      func makeWork() {
          for employee in employees {
              employee.work()
          }
      }
  }

  class Developer: Employee {
      func work() {
          print("coding")
      }
  }

  class Designer: Employee {
      func work() {
          print("design")
      }
  }
  ```
