정의

책임 연쇄 패턴은 핸들러들의 체인을 따라 요청을 처리하는 행동 디자인 패턴입니다.

따라서 순서가 굉장히 중요합니다. 

각 핸들러는 주어진 요청에 대한 처리를 담당하게 됩니다. (요청을  처리할지 말지, 다음 체인으로 넘길지 등등)

 

 

코드

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class CoREx {
	//커맨드 객체
	static class Person {
		String name;
		String sex;
		int age;
		public Person(String name, String sex, int age) {
			this.name = name;
			this.sex = sex;
			this.age = age;
		}
		@Override
		public String toString() {
			return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
		}
	}
	//각 요소를 요청이라고 가정한다.
	static List<Person> persons = new ArrayList<>();
	static {
		persons.add(new Person("김필터", "남", 20));
		persons.add(new Person("임자바", "남", 33));
		persons.add(new Person("이자바", "여", 22));
		persons.add(new Person("김자바", "여", 18));
		persons.add(new Person("이육사", "남", 27));
		persons.add(new Person("김육사", "여", 15));
		persons.add(new Person("박세종", "남", 30));
		persons.add(new Person("김세종", "남", 30));
	}
	//핸들러 
	static class Filter<T>{
		//나의 다음 체인 참조변수
		private Filter<T> nextFilter;
		//요구 사항
		private final Predicate<T> predi;
		
		protected Filter(Predicate<T> predi) {
			this.predi = predi;
		}
		@SafeVarargs //필터 체인 형성
		public static <T> Filter<T> createFilterChain(Filter<T> first, Filter<T>...filters){
			Filter<T> nowFilter = first;
			for(Filter<T> filter : filters) {
				nowFilter.nextFilter = filter;
				nowFilter = filter;
			}
			return first;
		}
		public boolean check(T data) {
			return predi.test(data) ? nextCheck(data) : false;
		}
		public boolean nextCheck(T data) {
			return nextFilter == null ? true : nextFilter.check(data);
		}
	}
	
	public static void main(String[] args) {
		//필터체인
		Filter<Person> filterChain = Filter.createFilterChain(
				new Filter<>(per -> per.age>=20)
				,new Filter<>(per -> per.sex.startsWith("남"))
				,new Filter<>(per -> per.name.startsWith("김"))
				);
		for(Person person : persons) {
			if(filterChain.check(person)) {
				System.out.println(person);
			}
		}
	}
}

결과

Person [name=김필터, sex=남, age=20]
Person [name=김세종, sex=남, age=30]

Filter는 사실 인터페이스나 추상클래스로 다루는 것이 더 좋으나, 편의상 일반 클래스로 구현

 

유사한 구조는 스프링 시큐리티에서 볼 수 있다.

 

 

'개발 > 디자인 패턴' 카테고리의 다른 글

생성 - 프로토타입(Prototype)  (0) 2023.05.13
구조 - 플라이웨이트(Flyweight)  (0) 2023.05.09
구조 - 빌더 패턴(Builder)  (0) 2023.05.03

타입의 계층

트럼프 계층

트럼프는 트럼프 인간을 포괄하는 일반적인 개념이다.

트럼프 인간은 트럼프보다 특화된 행동을 하는 특수한 개념이다.

개념 사이의 관계를  일반화/특수화(generalization/specialization)관계라고 한다.

부분 집합

 

일반화/특수화 관계

일반적이라는 말은 포괄적이라는 의미를 내포한다.

특수하다는 것은 일반적인 개념보다 범위가 좁다는 것을 의미한다.

 

객체지향에서는 행동이 중요하다고 했다.

내부의 상태가 일반적인지 특수한지가 중요하지 않다.

일반화/특수화 개념을 대입하면 일반적인 행동을 하느냐 특수한 행동을 하느냐가 것이다.

, 객체의 일반화/특수화 관계에 있어서도 중요한 것은 객체가 내부에 보관한 데이터가 아니라 객체가 외부에 제공하는 행동이다.

 

그렇다면 행동의 관점에서 일반적 타입과 특수한 타입은 무엇일까?

일반적 타입이란 특수한 타입이 가진 모든 행동들 중에서 일부 행동만을 가지는 타입이다.

특수한 타입이란 일반적인 타입이 가진 모든 타입을 포함하지만 거기에 더해 자신만의 행동을 추가하는 타입을 가리킨다.

따라서 일반적인 타입은 툭수한 타입보다 적은 수의 행동을 가지고

특수한 타입은 일반적인 타입 행동을 포함하며 보다 많은 수의 행동을 가진다.

 

여기서 주의할 점은 타입의 내연을 의미하는 행동의 가짓수와 외연을 의미하는 집합의 크기는 서로 반대라는 사실이다.

일반화/특수화 관계에서 일반적인 타입은 특수한 타입보다 적은 수의 행동을 가지지만 크기의 외연 집합을 가진다. 특수한 타입은 일반적인 타입보다 많은 수의 행동을 가지지만 적은 크기의 외연 집합을 가진다.

슈퍼타입과 서브타입

일반화/특수화 관계를 타입으로 바꾼

일반적인 타입을 슈퍼타입(Supertype), 특수한 타입을 서브타입(Subtype)이라 한다.

 

역시나 슈퍼타입과 서브타입에서 중요한 것은 타입 간의 관계가 행동에 의해 결정된다는 것이다.

 

어떤 타입이 다른 타입의 서브타입이 되기 위해서는 행위적 호환성을 만족시켜야 한다.

서브타입은 슈퍼타입을 대체할 있어야 한다.

 

일반화는 추상화를 위한 도구다

추상화 번째 원칙, 중요한 부분 강조를 위해 불필요한 세부 사항을 제거해 단순화

일반화/특수화 계층은 번째 원칙의 예시가 된다.

 

거의 대부분의 경우에 분류와 일반화/특수화 기법을 동시에 적용하게 된다.

 

 

정적 모델

타입의 목적

인간의 인지 능력으로 시간에 따라 동적으로 변하는 객체의 복잡성을 극복하기가 너무 어렵기 때문에 타입을 사용한다.

 

앨리스가 어떤 음식을 먹을 마다 키와 ,다리 길이가 시시각각 달라진다. 하지만 모든 경우에 앨리스는 단지 앨리스일 뿐이다.

 

앨리스라고 하는 객체의 상태는 변하지만 앨리스를 다른 객체와 구별할 있는 식별성은 동일하게 유지된다.

 

타입은 시간에 따라 동적으로 변하는 앨리스의 상태를 시간과 무관한 정적인 모습으로 다룰 있게 해준다.

아래 그림과 같이 앨리스의 상태에 복잡성을 부과하는 시간이라는 요소를 제거함으로써 시간에 독립적인 정적인 모습으로 앨리스를 생각할 있게 해준다.

 

 

 

그래서 결국 타입은 추상화다

어떤 시점에 앨리스에 관해 생각할 불필요한 시간이라는 요소와 상태 변화라는 요소를 제거하고 철저하게 정적인 관점에서 앨리스의 모습을 묘사하는 것을 가능하게 해준다.

 

타입은 추상화다. 타입을 이용하면 객체의 동적인 특성을 추상화할 있다. 결국 타입은 시간에 따른 객체의 상태 변경이라는 복잡성을 단순화할 있는 효과적인 방법인 것이다.

 

 

동적 모델과 정적 모델

객체를 생각할 가지 모델

 

첫째, 객체가 특정 시점에 구체적으로 어떤 상태를 가지느냐.

이를 객체의 스냅샷(snapshot)이라고 한다.

UML에서 스냅샷은 객체 다이어그램이라고도 불린다.

스냅샷처럼 실제로 객체가 살아 움직이는 동안 상태가 어떻게 변하고 어떻게 행동하는지를 포착하는 것을 동적 모델(dynamic model)이라고 한다.

 

둘째, 객체가 가질 있는 모든 상태와 모든 행동을 시간에 독립적으로 표현하는 것이다.

이를 타입 모델(type diagram)이라고 한다.

모델은 동적으로 변하는 객체의 상태가 아니라 객체가 속한 타입의 정적인 모습을 표현하기 때문에 정적모델(static model)이라 한다.

 

클래스를 만드는 행위가 정적인 모델링

디버그를 위해 상태 변경을 추적하는 것은 동적 모델링을 탐험하는

 

 

클래스

객체지향 프로그래밍 언어에서 정적인 모델은 클래스를 이용해 구현된다.

따라서 타입을 구현하는 가장 보편적인 방법은 클래스를 이용하는 것이다.

타입을 구현한다고 표현한 것은 클래스와 타입은 동일한 것이 아니라는 뜻이다.

타입은 객체를 분류하기 위해 사용하는 개념이다.

반면 클래스는 단지 타입을 구현할 있는 여러 구현 메커니즘 하나일 뿐이다.

실제로 자바스크립트와 같은 프로토타입 기반 언어에는 클래스가 존재하지 않는다.

 

객체를 분류하는 기준은 타입이며, 타입을 나누는 기준은 객체가 수행하는 행동이다.

 

객체지향에서 중요한 것은 동적으로 변하는 객체의 상태와 상태를 변경하는 행위다.

클래스는 타입을 구현하기 위해 프로그래밍 언어에서 제공하는 구현 메커니즘이다.

 

 

 

 

행동

상태와 행동

객체의 상태를 변경하는 것은 객체의 자발적인 행동뿐이다.

앨리스의 키가 작아진 이유는 앨리스가 음료를 마신 행동 때문이다.

 

객체의 행동에 의해 객체의 상태가 변경된다는 것은 행동이 부수 효과(side effect) 초래한다는 것을 의미한다.

부수 효과 개념을 이용하면 객체의 행동을 상태 변경의 관점에서 쉽게 기술할 있다.

앨리스가 케이크를 먹는 행위는 앨리스의 키를 작게 변화시키고 케이크의 양을 줄이는 부수 효과를 야기한다.

 

객체의 행동은 객체의 상태를 변경시키지만 행동의 결과는 객체의 상태에 의존적이다.

int sum = 20;  상태

sum = add(sum, 20);  //행동은 상태를 변경시킨다

현재 sum 40// 행동의 결과는 상태에 의존적이다.

 

 

앨리스 과거 행동을 돌아볼 필요 없이 앨리스의 키와 위치라는 상태 값을 이용해 간단하게 서술할 있다.

  • 앨리스의 키가 40센티미터 이하라면 문을 통과할 수 있다.
  • 문을 통과한 후에 앨리스의 위치는 아름다운 정원으로 바뀌어야 한다.

 

상태를 이용하면 복잡한 객체의 행동을 쉽게 이해할 있다.

협력과 행동

객체가 다른 객체와 협력하는 유일한 방법은 다른 객체에게 요청 보내는 것이다.

요청을 수신한 객체는 요청을 처리하기 위한 적절한 행동을 한다.

따라서 객체의 행동은 객체가 협력에 참여할 있는 유일한 방법이다.

 

객체는 협력에 참여하는 과정에서 자기 자신의 상태뿐만 아니라 다른 객체의 상태 변경을 유발할 도있다.

 

객체의 행동은 가지 부수효과를 가질 있다.

  • 객체 자신의 상태 변경
  • 행동 내에서 협력하는 다른 객체에 대한 메시지 전송

행동이란 외부의 요청 또는 수신된 메시지에 응답하기 위해 동작하고 반응하는 활동이다. 행동의 결과로 객체는 자신의 상태를 변경하거나 다른 객체에게 메시지를 전달할 있다. 객체는 행동을 통해 다른 객체와의 협력에 참여하므로 행동은 외부에 가시적이어야 한다.

상태 캡슐화

현실 세계의 객체와 객체지향 세계의 객체 사이에는 차이가 있다.

현실 앨리스는 능동적인 존재로 스스로 음료를 마실 있지만 음료는 스스로는 아무것도 없는 수동적 존재다.

 

객체지향의 세계에서 모든 객체는 자신의 상태를 스스로 관리하는 자율적인 존재다.

, 음료 객체도 자신이 스스로 양을 줄일 있어야 하며, 앨리스 객체가 음료의 상태를 변경 할 없다. 단지 음료 객체에게 자신이 음료를 마셨다는 메시지를 전달할 있을 뿐이다.

앨리스가 음료를 마셨다고 메시지를 보내도 음료의 량을 줄일 지 말지는 음료 객체가 결정할 사항이다. 앨리스는 음료의 양이 줄어들 것이라는 것을 믿고 요청을 전달할 뿐이다.

 

앨리스에게 전달되는 메시지는 drinkBeverage()

음료에게 전달되는 메시지 drunken(quantity)

메시지만 보고 앨리스의 키와 음료의 양이 줄어든다는 상태 변경을 예상할 있나?

전혀 알지 못한다.

 

이것이 캡슐화가 의미하는 것이다. 객체는 상태를 캡슐 안에 감춰둔 외부로 노출하지 않는다. 객체가 외부에 노출하는 것은 행동뿐이며, 외부에서 객체에 접근할 있는 유일한 방법 역시 행동뿐이다.

 

객체의 행동을 유발하는 값은 외부로부터 전달된 메시지지만 객체의 상태를 변경할지 여부는 객체 스스로 결정한다.

사실 객체에게 메시지를 전달하는 외부의 객체는 메시지를 수신하는 객체의 상태가 변경된다는 사실조차 알지 못한다.

메시지 송신자는 단지 자신의 요구를 메시지로 포장해서 전달할 뿐이다. 메시지를 해석하고 그에 반응해서 상태를 변경할지 여부는 전적으로 메시지 수신자의 자율적인 판단에 따른다.

송신자가 상태 변경을 기대하더라도 수신자가 자신의 상태를 변경하지 않는다면 송신자가 간섭할 있는 어떤 여지도 없다.

 

상태를 외부에 노출시키지 않고 행동을 경계로 캡슐화하는 것은 결과적으로 객체의 자율성을 높힌다.

객체의 자율성이 높아질 수록 객체간 협력은 유연하고 간결해진다.

 

결론적으로 상태를 정의된 행동 집합 뒤로 캡슐화하는 것은 객체의 자율성을 높이고 협력을 단순하고 유연하게 만든다. 이것이 상태를 캡슐화해야 하는 이유다.

 

식별자

객체란 인간의 인지 능력을 이용해 식별 가능한 경계를 가진 모든 사물

객체가 식별 가능하다는 것은 객체를 서로 구별할 있는 특정한 프로퍼티 객체 안에 존재한다는 것을 의미한다. 프로퍼티를 식별자 한다.

 

단순한 값과 객체의 가장 차이점은 값은 식별자를 가지지 않지만 객체는 식별자를 가진다.

 

값은 숫자, 문자열, 날짜, 시간, 변하지 않는 양을 모델링한다. 때문에 불변 상태(immutable state) 가진다고 말한다.

 

값이 같은지 여부는 값의 상태를 보고 결정한다. 인스턴스가 같은 상태를 가지면 동일하다고 판단한다. 이처럼 상태를 이용해 값이 같은지 판단할 있는 성질을 동등성(equality)이라 한다.

 

객체는 시간에 따라 변경되는 상태를 포함한다. 행동을 통해 상태를 변경한다.

따라서 객체는 가변 상태(mutable state) 가진다고 말한다.

타입이 같은 객체의 상태가 완전히 똑같더라도 객체는 독립적인 별개의 객체로 다뤄야 한다.

 

객체도 같거나 다르다고 판단할 있는 프로퍼티를 가진다. 객체의 상태가 다르더라도 식별자가 같다면 객체를 같은 객체로 판단할 있다.

이처럼 식별자를 기반으로 객체가 같은지를 판단할 있는 성질을 동일성(identical)이라고 한다.

 

상태를 기반으로 객체의 동일성을 판단할 없는 이유는 시간에 따라 객체의 상태가 변하기 때문이다. 따라서 식별자를 두어 객체의 동일성을 판단하는 것이다.

 

식별자란 어떤 객체를 다른 객체와 구분하는 데 사용하는 객체의 프로퍼티다. 값은 식별자를 가지지 않기 때문에 상태를 이용한 동등성 검사를 통해 두 인스턴스를 비교해야 한다. 객체는 상태가 변경될 수 있기 때문에 식별자를 이용한 동일성 검사를 통해 두 인스턴스를 비교할 수 있다.

 

객체지향 프로그래밍 언어에서 값과 객체의 차이점을 혼동할 수도 있다.

근본적으로 값도 클래스로 표현되기 때문이다. Integer,Boolean…(물론 자바는 기본형도 지원)

때문에 별도의 용어를 쓰는 경우가 있다. 객체는 식별자가 없는 객체이다.

참조객체(reference object) 또는 엔티티(entity) 식별자가 있는 객체

 

지금까지 객체의 중요한 특성인 상태, 행동, 식별자에 대한 요약

객체는 상태를 가지며 상태는 변경 기능하다.

객체의 상태를 변경시키는 것은 객체의 행동이다.

행동의 결괴는 상태에 의존적이며 상태를 이용해 서술할 수 있다.

행동의 순서가 실행 결과에 영향을 미친다.

객체는 어떤 상태에 있더라도 유일하게 식별 기능하다.

 

 

 

 

 

 

 

 

객체지향과 인지 능력

인간은 직접적으로 지각할 있는 사물을 넘어 추상적인 사물까지도 객체로 인식할 있는 능력이 있다. 어제 주문내역과 오늘 주문내역을 구분하는 , 출금 계좌에서 동일한 입금 계좌로 동일한 금액을 이체하더라도 구분이 가능하다.

물리적인 실체는 존재하지 않더라도 인간이 쉽게 구분하고 하나의 단위로 인지할 있는 개념적인 객체의 일종이다.

 

복잡한 세상에서 인간은 단순한 객체들로 주변을 분해함으로써 세상을 이해하려고 노력한다.

, 객체란 인간이 분명하게 인지하고 구별할 있는 물리적인 또는 개념적인 경계를 지닌 어떤 이다.

 

객체지향 패러다임은 인간이 인지할 있는 다양한 객체들이 모여 현실 세계를 이루는 것처럼 소프트웨어의 세계 역시 인간이 인지할 있는 다양한 소프트웨어 객체들이 모여 이뤄져 있다는 믿음에서 출발한다.

객체지향 패더라임의 목적은 현실 세계를 모방하는 것이 아니라 현실 세계를 기반으로 새로운 세계를 창조하는 것이다. 따라서 현실 세계 객체와 소프트웨어 세계의 객체와는 전혀 다른 모습을 보이는 것이 일반적이다.

 

예로 현실세계 전등은 사람없이 껏다 킬수 없다. 소프트웨어 전등은 자동으로 가능하다.

 

객체, 그리고 이상한 나라

이상한 나라의 앨리스

앨리스 이야기로 예시를 든다. 이야기 내용을 요약하면,

작은 문을 통과하기 위해, 주변 음식을 먹으면서 몸집을 줄였다가 늘렸다 한다.

앨리스 객체

앞의 이야기는 앨리스가 겪고 있는 키의 변화에 초점을 맞추고 있다.

앨리스는 정원으로 가기 위해 자신의 상태 계속 변화시켰다.

이런 상태변화는 앨리스의 행동이다. 앨리스 행동에 따라 앨리스 상태가 변한다.

 

상태를 결정하는 것은 행동이지만 행동의 결과를 결정하는 것은 상태이다.

예를들어, 앨리스 130cm 여기에 케이크를 먹어서 150cm 커졌다. 그럼 원래 상태 130cm + 150cm

280cm 된다.

, 앨리스가 행동의 결과는 앨리스의 상태에 의존적이다.

어떤 행동의 성공 여부는 이전에 어떤 행동들이 발생했는지에 영향을 받는다는 사실도 중요하다

앨리스가 문을 성공적으로 통과하기 위해서는 문을 통과할 있을 정도로 충분히 몸을 작게 중여야 한다. 따라서 앨리스는 문을 통과하기 전에 먼저 키를 작게 줄이기 위해 안의 음료나 케이크를 먹어야 한다.

이것은 행동 간의 순서가 중요하다는 것을 의미한다. 문을 통과하는 행동이 성공하려면 음료나 케이크를 먹는 행동이 선행돼야만 한다.

 

 

객체, 그리고 소프트웨어 나라

물리적인 또는 개념적인 사물은 어떤 것이라도 객체가 있다.

인간의 인지 능력 안에서 개수를 있고, 다른 사물과 구분할 있으며, 생성 시점을 있고, 독립적인 하나의 단위로 인식할 있는 모든 사물은 객체다.

 

객체의 다양한 특성을 효과적으로 설명하기 위해선 객체를 상태(state), 행동(behavior), 식별자(identity) 지닌 실체로 보는 것이 가장 효과적이다.

 

책에서 객체를 다음과 같이 정의한다.

객체란 식별 가능한 개제 또는 사물이다. 객체는 자동차처럼 만질 수 있는 구체적인 사물일 수도 있고, 시간처럼 추상적인 개념일 수도 있다. 객체는 구별 가능한 식별자, 특징적인 행동, 변경 가능한 상태를 가진다. 소프트웨어 안에서 객체는 저장된 상태와 실행 가능한 코드를 통해 구현된다.

 

 

상태

상태가 필요한가

객체가 주변 환경과의 상호작용에 어떻게 반응하는가는 시점까지 객체에 어떤 일이 발생했느냐에 좌우된다.

예를들어 비행기를 이용하려면 탑승 전에 발권이 필수다.

자판기에 음료를 먹기위해서는 충분한 돈을 넣어야 한다.

 

공통점은 어떤 행동의 결과는 과거에 어떤 행동들이 일어났었느냐에 의존한다는 것이다.

 

일반적으로 과거에 발생한 행동이력을 통해 현재 발생한 행동의 결과를 판단하는 방식은 복잡하고 번거롭고 이해하기 어렵다.

행동과정과 결과를 단순하게 기술하기 위한 상태라는 개념을 고안했다.

비행기 탑승 가능 여부는 항공권의 발권 상태를 보고 예측할 있다.

자판기는 현재까지 투입된 금액의 상태를 기억한다.

 

상태를 이용하면 과거의 모든 행동이력을 설명하지 않고도 행동의 결과를 쉽게 예측하고 설명할 있다.

앨리스가 과거에 어떤 행동을 했었는지 모르더라도 앨리스의 키만 알면 문을 통과할 있는지 여부를 쉽게 판단할 있다.

앨리스 키와 문높이 두가지 상태만 알면 문을 통과하는 행동의 결과를 쉽게 예측할 있다.

 

 

상태와 프로퍼티

앨리스는 객체다. 앨리스의 키를 줄이거나 늘리기 위해 사용하는 음료, 케이크, 부채, 버섯 모두 객체다. 모두 뚜렷한 경계를 가지며 식별 가능하고 상태와 행동을 지니고 있다.

 

그러나 세상에 모든 것들이 객체인 것은 아니다. 앨리스의 '' 위치' 객체가 아니다. 음료의 '' 객체가 아니다. 문이 열렸는지 '여부' 객체가 아니다

, 숫자, 문자열, , 속도, 시간, 날짜, 참/거짓과 같은 단순한 값들은 객체가 아니다.

단순값들은 자체로 독립적인 의미를 가지기보다는 다른 객체의 특성을 표현하는데 사용된다.

 

때로는 단순한 값이 아니라 객체를 사용해 다른 객체의 상태를 표현해야 때가 있다.

앨리스가 음료를 들고 있는 상태를 표현하기 위해 /거짓이 아닌 음료 객체를 이용해 표현하는 것이다. 음료를 들고있나 없나는 음료객체와 연결됐나 안됐나로 구분한다.

결론적으로 모든 객체의 상태는 단순한 값과 객체의 조합으로 표현할 있다.

객체의 상태를 구성하는 모든 특징을 통틀어 객체의 프로퍼티(property)라고 한다.

앨리스 기준 ,위치,음료가 프로퍼티다.

일반적으로 프로퍼티는 변하지 않는 정적이다. 반면 프로퍼티의 값은 변할 있는 동적이다.

 

다른 시점에서 앨리스를 봤는데 음료와 연결이 없다. 음료를 버린 것으로 보인다.

시점에서 앨리스는 음료에 대한 상태를 모른다.

이처럼 객체와 객체 사이의 의미 있는 연결을 링크(link)라고 한다.

 

객체 사이 링크를 통해서만 요청을 주고 응답을 받을 있다.

, 링크를 통해서만 협력이 가능하다

 

객체 간의 선으로 표현되는 링크와 달리 객체를 구성하는 단순 값은 속성(attribute)이라고 한다.

따라서 앨리스의 키와 위치는 속성이다.

 

조합하면 프로퍼티는 단순 값인 속성과 객체와 연결을 가르키는 링크 조합이다.

 

이 책에서는 객체의 상태를 다음과 같이 정의하기로 한다.

상대는 특정 시점에 객체가 가지고 있는 정보의 집합으로 객체의 구조적 특징을 표현한다.

객체의 상태는 객체에 존재하는 정적인 프로퍼티와 동적인 프로퍼티 값으로 구성된다.

객체의 프로퍼티는 단순한 값과 다른 객체를 참조하는 링크로 구분할 수 있다.

 

객체는 자율적인 존재라는 것을 명심하라

객체지향의 세계에서 객체는 다른 객체의 상태에 직접적으로 접근할 수도, 상태를 변경할 수도 없다.

자율적인 객체는 스스로 자신의 상태를 책임져야 한다.

외부의 객체가 직접적으로 객체의 상태를 주무를 없다면 간접적으로 객체의 상태를 변경하거나 조회 있는 방법이 필요하다.

 

행동은 다른 객체로 하여금 간접적으로 객체의 상태를 변경하는 것을 가능하게 한다.

객체지향의 기본 사상은 상태와 상태를 조작하기 위한 행동을 하나의 단위로 묶는 것이라는 점을 기억하라

객체는 스스로의 행동에 의해서만 상태가 변경되는 것을 보장함으로써 객체의 자율성을 유지한다.

 

 

 

 

 

협력 속에 사는 객체

역할, 책임, 협력

실제로 협력에 참여하는 주체는 객체.

실행 중 인 어플리케이션을 보면 객체들간에 메시지를 주고받으면서 협력하는 것을 있다. 이렇듯 객체가 없으면 객체지향 세계 역시 아무런 의미가 없다. 객체지향이라 부르는 이유는 패러다임의 중심에 객체가 있기 때문이다.

 

객체는 애플리케이션의 기능을 구현하기 위해 존재한다. 작은 기능조차 객체 혼자 감당하기에는 버거울 정도로 복잡 거대하다. 때문에 객체는 다른 객체와의 협력을 통해 기능을 구현하게 된다.

따라서 협력이 얼마나 조화를 이루는지 결정하는 것은 객체다.

결국 협력의 품질을 결정하는 것은 객체의 품질이다.

 

협력 공동체의 일원으로 객체는 가지 덕문을 갖춰야 한다.

첫째, 객체는 충분히 협력적이어야 한다.

모든 것을 스스로 처리하려고 하는 전지전능한 객체는 내부적인 복잡도에 의해 자멸하고 만다

 

둘째, 객체가 충분히 자율적이어야 한다.

자기 스스로의 원칙에 따라 어떤 일을 하거나 자기 스스로를 통제하여 절제하는 것을 의미한다.

객체는 다른 객체에 명력에 복종하는 것이 아니라 요청에 응답할 뿐이다. 어떤방식으로 응답할지는 객체 스스로 판단하고 결정한다.

심지어 요청에 응할지 여부도 객체 스스로 결정할 있다.

 

객체 공동체에 속한 객체들은 공동의 목표를 달성하기 위해 협력에 참여하지만 스스로의 결정과 판단에 따라 행동하는 자율적인 존재.

 

 

상태와 행동을 함께 지닌 자율적인 객체

객체를 상태(state) 행동(behavior) 함께 지닌 실체라고 정의한다.

이 말은 객체가 협력에 참여하기 위해 어떤 행동을 한다면 행동을 하는 필요한 상태도 함께 지니고 있어야 한다는 것을 의미한다.

 

객체가 협력에 참여하는 과정 속에서 스스로 판단하고 스스로 결정하는 자율적인 존재로 남기 위해서는 필요한 행동과 상태를 함께 지니고 있어야 한다.

 

객체의 자율성은 객체의 내부와 외부를 명확하게 구분하는 것으로부터 나온다.

객체의 사적인 부분은 객체 스스로 관리하고 외부에서 일체 간섭할 없도록 차단해야 하며, 객체의 외부에서는 접근이 허락된 수단을 통해서만 객체와 의사소통해야 한다.

객체는 다른 객체가 무엇(What) 수행하는지는 있지만 어떻게(how) 수행하는지에 대해서는 없다.

 

커피를 주문하는 협력 과정에 참여한 손님과 캐시어, 바리스타는 외부의 간섭을 받지 않고 스스로 생각하고 스스로 판단하는 자율적인 존재였다.

객체의 관점에서 자율성이란 자신의 상태를 직접 관리하고 상태를 기반으로 스스로 판단하고 행동할 있음을 의미한다.

객체는 행동을 위해 필요한 상태를 포함하는 동시에(바리스타는 커피 제조 방법을 기억하고 있다) 특정한 행동을 수행하는 방법을 스스로 결정할 있어야 한다.(바리스타는 자신이 알고 있는 방법에 따라 커피를 제조한다)

따라서 객체는 상태와 행위를 하나의 단위로 묶은 자율적인 존재다.

 

과거 전통적인 개발 방법은 데이터와 프로세스를 엄격하게 구분한다

이에 반해 객체지향에서는 데이터와 프로세스를 객체라는 하나의 안에 함께 묶어 놓음으로써 객체의 자율성을 보장한다.

자율적인 객체로 구성된 공동체는 유지보수가 쉽고 재사용이 용이한 시스템을 구축할 있는 가능성을 제시한다.

 

 

 

협력과 메시지

커피를 주문하기 위해 협력하는 사람들은 자신의 책임을 다하기 위해 다른 사람들에게 도움을 요청한다.

다양한 요청 방법이 있을 것이다.

 

객체지향의 세계에서는 오직 가지 의사소통 수단만이 존재한다. 이를 메시지라고 한다.

객체가 다른 객체에게 요청하는 것을 메시지를 전송한다고 다른 객체로부터 요청을 받는 것을 메시지를 수신한다고 말한다.

결과적으로 객체는 협력을 위해 다른 객체에게 메시지를 전송하고 다른 객체로부터 메시지를 수신한다.

 

 

메서드와 자율성

객체는 다른 객체와 협력하기 위해 메시지를 전송한다.

수신자는 먼저 수신된 메시지를 이해할 있는지 여부를 판단한 미리 정해진 자신만의 방법에 따라 메시지를 처리한다. 이처럼 체가 수신된 메시지를 처리하는 방법을 메서드라고 부른다.

 

객체지향 프로그래밍 언어에서 메서드는 클래스 안에 포함된 함수 또는 프로시저를 통해 구현된다.

다른 프로그래밍 언어와 객체지향 프로그래밍 언어를 구분 짓는 핵심적인 특징 하나다.

 

메시지(요청) 메서드의 분리는 객체의 협력에 참여하는 객체들 간의 자율성을 증진시킨다.

커피를 주문하는 협력과정에서 커피 제조를 요청받은 바리스타는 커피머신, 수제 커피 등등 제조 방법을 자율적으로 선택할 있다.

 

객체지향에 대입하면 커피 주문이 요청, 커피 제작하는 방법은방법은 메서드다

커피 제조를 요청한 사람은 어떻게 커피를 제조하는지 구체적인 방법을 모른다.(자율성 보장)

 

외부의 요청이 무엇인지 표현하는 메시지와 요청을 처리하기 위한 구체적인 방법인 메서드를 분리하는 것은 객체의 자율성을 높이는 핵심 메커니즘이다. 이것은 캡슐화라는 개념과도 깊이 관련돼 있다.

 

 

 

 

객체지향의 본질

객체지향이란 시스템을 상호작용하는 자율적인 객체들의 공동체로 바라보고 객체를 이용해 시스템을 분할하는 방법

자율적인 객체란 상태와 행위를 함께 지니며 스스로 자기 자신을 책임지는 객체를 의미한다.

객체는 시스템의 행위를 구현하기 위해 다른 객체와 협력한다. 각 객체는 협력 내에서 정해진 역할을 수행하며 역할은 관련된 책임의 집합이다.

객체는 다른 객체와 협력하기 위해 메시지를 전송하고, 메시지를 수신한 객체는 메시지를 처리하는 데 적합한 메서드를 자율적으로 선택한다.

 

 

객체를 지향하라

클래스가 객체지향 프로그래밍 언어의 관점에서 매우 중요한 구성요소인 것은 분명하다

하지만 객체지향의 핵심을 이루는 중심 개념이라고 말하긴 무리가 있다.

자바스크립트 같은 프로토타입 기반의 객체지향 언어에서는 클래스가 존재하지 않으며 오직 객체만이 존재한다. 프로토타입 기반의 객체지향객체지향 언어에서는 상속 역시 클래스가 아닌 객체 간의 위임 메커니즘을 기반으로 한다.

지나치게 클래스를 강조하는 프로그래밍 언어적인 관점은 객체의 캡슐화를 저해하고 클래스를 서로 강하게 결합시킨다.

 

객체지향 설계의 관점을 코드를 담는 클래스의 관점에서 메시지를 주고받는 객체의 관점으로 변환해야 한다.

중요한 것은 어떤 클래스가 필요한가 가 아니라 어떤 객체들이 어떤 메시지를 주고받으며 협력하는 가다. 클래스는 객체들의 협력 관계를 코드로 옮기는 도구에 불과하다.

 

클래스의 구조와 메서드가 아니라 객체의 역할, 책임, 협력에 집중하라. 객체지향은 객체를 지향하는 것이지 클래스를 지향하는 것이 아니다.

 

+ Recent posts