상태 , 행동 , 식별자
-
객체지향 패러다임
지식을 추상화 하고 , 추상화한 지식을 객체내에 캡슐화 하여 복잡성을 관리하고 , 객체의 지식과 행동을 구조화
-
객체
-
하나의 단위로 인식가능한 사물이다.
-
행동 , 상태 , 식별자를 가지는 사물
-
현실의 문제를 해결하기위해서 소프트웨어 세계를 창조합니다.
하나의 문제를 해결하기위해선 여러개의 작은 동작들로 나눌 수 있습니다.
각각의 동작들은 책임을 가지는 객체가 해결하고 , 협력을 통해 문제를 해결합니다.
-
행동과 상태
-
행동을 수행하는 객체들이 행동의 결과를 결정하는데에는 과거의 행동의 이력이 연관을 가진다.
-
과거의 행동의 이력을 표현할 수 있는 효과적인 방법은 상태 로 표현하는 것이다.
-
과거의 행동이 상태를 변경하므로 상태는 행동의 결과에 의존한다
-
또 행동의결과는 상태에 의존한다
-
플레이어가 하는 공격이라는 행동은 플레이어가 과거에 어떤 무기를 장착하는 동작을 했는 지에 따라 달라진다. 과거의 무기를 장착하는 행동에 따라 달라지는 데 이걸 어떻게 공격하는 행동에 연관을 가지게 할것인가? 상태 라는 개념이 생기면 편하다. 무기를 장착하는 행동은 플레이어의 공격력이라는 상태를 수정한다. 그 수정한 공격력상태는 이후 있을 공격이라는 행동에 영향을 끼친다. 이렇게 행동 -> 상태 -> 행동 이런 식으로 계속적으로 영향을 끼친다.
-
예) 게임내의 캐릭터와 몬스터간의 공격
-
\GameObject
-
class GameObject{ private(set) var hp : Int var attackPower : Int var defensePower : Int init(hp:Int,attackPower:Int,defensePower:Int){ self.hp = hp self.attackPower = attackPower self.defensePower = defensePower } func attack(target: GameObject){ target.damaged(amount: self.attackPower) } func damaged(amount:Int){ let calculatedDamageAmount = amount - self.defensePower/10 self.hp -= calculatedDamageAmount } }
-
Player
-
class Player:GameObject{ var weapon : Weapon? init(hp: Int, attackPower: Int, defensePower: Int,weapon:Weapon = Weapon(originPower: 5, phaseOfReinforce: 0)) { super.init(hp: hp, attackPower:weapon.power ,defensePower: defensePower) self.weapon = weapon } override func attack(target: GameObject) { guard let monster = target as? Monster else { print("올바른 타겟이 아닙니다") return } super.attack(target: monster) } }
-
Weapon
-
struct Weapon { var power : Int { return originPower + phaseOfReinforce*10 } var originPower :Int var phaseOfReinforce : Int mutating func reinforce(){ self.phaseOfReinforce+=1 } }
-
Monster
-
class Monster : GameObject{ override func attack(target: GameObject) { guard let player = target as? Player else { print("올바른 타겟이 아닙니다") return } super.attack(target: player) } }
-
World
-
let sward = Weapon.init(originPower: 10, phaseOfReinforce: 0) let warrior = Player.init(hp: 100, attackPower: 5, defensePower: 10,weapon: sward) let bow = Weapon.init(originPower: 5, phaseOfReinforce: 0) let archer = Player.init(hp: 100, attackPower: 5, defensePower: 10,weapon: bow) let slime = Monster.init(hp: 50, attackPower: 5, defensePower: 5) warrior.attack(target: archer) // 올바른 타겟이 아닙니다 warrior.attack(target: slime) // slime.damage() 발생
-
상태( hp )는 행동( damaged() ) 의 이력에 따라서 값이 변경된다. - 과거의 행동들이 상태를 변경한다. 행동( attack() ) 의 결과는 상태( attackPower ) 에 의존한다. - 행동의 결과는 상태에 의존한다.
- 객체는 자율적이고 능동적이다
- Weapon.reinforce() - 무기는 스스로 강화되지는 않지만, 객체는 모두 능동적으로 행동한다.
- 외부에서는 메시지를 보낼뿐 상태는 객체 자신 스스로 결정한다.
- 객체는 자신의 행동의 결과를 자신 스스로 자율적으로 결정하기 때문에 , 외부에는 상태를 노출 할 필요가 없다
식별자
- 값을 표현하는 객체가 아닌 모두 식별자를 가진다.
- 객체는 가변적이다.
-
객체의 속성의 유무는 정적, 값은 동적으로 움직인다
-
hp 라는 속성 은 언제나 존재하나 , 수치는 바뀔수있다.
-
이유?
위에 말했듯이 객체는 가변적이다. 항상 변하는 값으로 객체를 식별할 수 는 없다.
-
예시
-
var monsterRed = Monster.init(hp: 50, attackPower: 5, defensePower: 5) var monsterBlue = Monster.init(hp: 50, attackPower: 5, defensePower: 5) // 둘은 동등한 능력을 가지나 , 분리된 객체이다. // 동등성은 만족하나 , 동일성은 만족하지 않는다. monsterRed.attackPower = 100 // 동등성은 언제든지 깨질 수있다.
설계시 고려할 사항
행동을 먼저 결정하고 상태를 결정해라
-
캡슐화를 저해할수 있다.
- 상태를 먼저 결정하게되면 , 상태위주의 코드를 짜기때문에 , 상태를 캡슐화하는 것이 어렵다.
-
협력을 저해할 수 있다.
- 협력을 함에 있어서 객체들은 각각 자신에 책임에 맞는 행동을 구현하고 , 행동은 상태에 의존해야 한다.
-
재사용을 방해할수 있다.
기타
-
쿼리 : 객체의 상태를 조회 ex) getter
-
명령 : 객체의 상태를 변경 ex) setter