블로그

윤대

[인프런 워밍업 0기 Day5] 한 걸음 더! 객체 지향으로 클린코딩!

!! 해당 글은 독자가 인프런 워밍업 0기를 수강하고 있다는 전제 하에 작성되었습니다 !!과제 수행에 있어 스프링부트 3.2.2 버전을 사용하고 있다는 점을 미리 알려드립니다!안녕하세요🙌! 인프런 워밍업 5일차 과제입니다!이번에는 클린코드의 중요성에 대하여 학습하고 클린코드를 작성하는 방법에 대해 배웠습니다!😎저는 이번 과제를 그동안 책으로만 공부했던 객체 지향을 적용하여 해결해보고자 했습니다.이론으로만 공부했기 때문에 많이 서툴 수 있다는 점! 그렇기에, 저의 말이 정답이 아니라는 점을 미리 말씀 드리며!지금부터 객체 지향을 향한 저의 여정을 소개하겠습니다! 🤸‍♂️💡과제 살펴보기아래는 과제로 주어진 지저분한 코드입니다! 바라보기만 해도 머리가 어지러운데요.. 😥public class Main { public static void main(String[] args) throws Exception { System.out.print("숫자를 입력하세요 : "); Scanner scanner = new Scanner(System.in); int a = scanner.nextInt(); int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0; for (int i= 0; i < a; i++) { double b = Math.random() * 6; if (b >= 0 && b < 1) { r1++; } else if (b >= 1 && b < 2) { r2++; } else if (b >= 2 && b < 3) { r3++; } else if (b >= 3 && b < 4) { r4++; } else if (b >= 4 && b < 5) { r5++; } else if (b >= 5 && b < 6) { r6++; } } System.out.printf("1은 d%번 나왔습니다.\n", r1); System.out.printf("2는 d%번 나왔습니다.\n", r2); System.out.printf("3은 d%번 나왔습니다.\n", r3); System.out.printf("4는 d%번 나왔습니다.\n", r4); System.out.printf("5는 d%번 나왔습니다.\n", r5); System.out.printf("6은 d%번 나왔습니다.\n", r6); } }위 코드는 결국 다음과 같은 동작을 수행합니다!주어지는 숫자를 하나 받는다.해당 숫자만큼 주사위를 던져, 각 숫자가 몇 번 나왔는지 알려준다.위 코드처럼 로직을 열거하여 프로그래밍 하는 방식을 절차 지향 프로그래밍이라 말하며, 저는 이 코드를 클린코드로 수정해야 합니다!위의 코드는 클린 코딩의 중요성을 위한 극단적인 예시일 뿐, 절차 지향이라 지저분한 것이 아닙니다!지나친 추상화는 오히려 코드의 가독성을 떨어트릴 수 있으니 무조건 '객체 지향이 좋다!'의 글이 아니라는 점 알아주세요!저는 위의 코드를 깔끔하게 바꾸기 위해서 아래와 같이 객체 지향의 형태로 수정하여 과제를 완수했습니다!public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); Dice luckyDice = UnknownDice.decideFaces(6); Note memoPad = new MemoPad(); Dealer dealer = Dealer.playWith(luckyDice, memoPad); System.out.print("숫자를 입력하세요 : "); dealer.rollDiceMultipleTimes(scanner.nextInt()); dealer.tellTheResult(); } }어떤가요? 내부 로직이 어떻게 되는지는 모르겠지만, 메소드명만을 보고도 원래의 코드와 똑같은 동작을 수행할 것이 기대할 수 있습니다!그렇다면, 내부는 어떻게 구현됐을까요? 내부 구현을 함께 살펴보기 전에 객체 지향이 무엇인지 짧게 설명 드리고 가겠습니다! 💡객체 지향 프로그래밍이란?객체 지향은 '프로그램이'라는 거대한 로직을 '객체'라는 작은 역할로 나누고, 그 '객체'들끼리 상호 협력하여 데이터를 처리하는 방식을 말합니다!어젯밤에 저는 오렌지를 하나 먹었는데요! 이 오렌지가 집에 오기 까지의 과정을 '프로그램'이라고 보겠습니다.그리고, 지금부터 오렌지의 여정을 절차 지향적으로 설명해보겠습니다! 😎먼저 오렌지 나무를 볕 좋은 곳을 찾아서 심고, 거름도 포대를 찢어서 뿌리 주변에 뿌려주고, 해충도 유기농을 위해 핀셋으로 잡아주고.. 설명이 끝도 없이 길어집니다!그렇다면 이번엔 오렌지의 여정을 객체 지향적으로 설명해볼까요?오렌지를 농부가 '재배'하고, 운송 회사가 '운송'하고, 마트에서 '판매'되어 저의 집까지 왔습니다!어떤가요? 훨씬 설명이 쉽고 이해하기 좋지 않은가요? 오렌지가 어떻게 재배되었는지, 운송되었는지, 판매되었는지 우리는 구체적으로 알 필요가 없습니다! 궁금하지도 않고요!이렇게 내부 구현을 숨기고, 역할 만을 외부에 공개하여 코드의 가독성을 올리고 협업을 용이하게 하는 것이 객체 지향의 장점입니다!이는 개체 지향의 단편적인 장점입니다! 더 많은 장점이 있지만, 지금은 클린코딩과 관련하여 추상화와 캡슐화로 인한 장점 만을 이야기하고 넘어가겠습니다! 😭😭 💡도메인 선정하기!  자! 이제 다시 과제로 넘어와 보겠습니다~ 위에서 객체 지향에서 중요한 것은 역할과 협력이라고 했습니다!우리는 요구 사항을 잘 읽고 작은 역할을 찾고 그 역할을 수행할 주인공(도메인)을 선정해야 합니다. 😎사용자로부터 숫자를 하나 입력 받는다.해당 숫자만큼 주사위를 던져, 각 숫자가 몇 번 나왔는지 알려준다. -> 핵심 로직!!저는 핵심 로직에서 두 가지 역할을 찾았습니다! 하나는 무작위의 수를 생성하는 것, 다른 하나는 생성된 수를 각각 세는 것입니다.그리고, 발견한 역할을 바탕으로 이를 수행할 두 가지 도메인을 만들었습니다.무작위 수를 생성하는 🎲주사위(Dice)와 이를 기록해주는 📃노트(Note)입니다!그렇다면, 이 둘을 재빠르게 설계해 볼까요?abstract public class Dice { private final int faces; protected Dice(int faces) { this.faces = faces; } protected int getFaces() { return this.faces; } abstract int throwDice(); } public interface Note { void record(Integer number); void printTheResult(); }다양한 경험을 위해, 저는 주사위는 추상 클래스로 노트는 인터페이스로 만들었습니다!Dice의 throwDice()는 주사위를 굴리는 행위를 나타내며 무작위 수를 생성합니다!Note의 record()는 입력되는 수를 기록하고 기록된 수는 printTheResult()를 통해 출력할 예정입니다!이렇게, 추상 클래스와 인터페이스로 만드는 이유는 해당 동작을 수행할 수 있다면 그게 무엇이든 역할을 대체할 수 있게 하기 위함입니다! 숫자를 기록하고 출력할 수 있다면 메모지던, 스케치북이던, 스마트폰이던 상관이 없습니다!이제 이 둘을 구현해보겠습니다!public class UnknownDice extends Dice { private UnknownDice(int faces) { super(faces); } public static UnknownDice decideFaces(int faces) { return new UnknownDice(faces); } @Override public int throwDice() { return (int) (Math.random() * super.getFaces()) + 1; } } import java.util.HashMap; import java.util.Map; public class MemoPad implements Note { private final Map<Integer, Integer> page = new HashMap<>(); @Override public void record(Integer number) { page.put(number, page.getOrDefault(number, 0) + 1); } @Override public void printTheResult() { for(Map.Entry<Integer, Integer> number : page.entrySet()){ System.out.printf("%d은(는) %d번 나왔습니다.\n", number.getKey(), number.getValue()); } } }이렇게, 구현이 끝이 났습니다! 그런데, 이럴 수가! 여전히 문제가 있습니다. 도메인을 구현한 것 만으로는 로직을 수행할 수가 없습니다..! 😥바로, 주사위와 노트를 어떻게 사용할 것인지 맥락(컨텍스트)이 없기 때문입니다! 💡컨텍스트 만들기!주사위는 무작위 수를 생성하고! 노트는 기록을 합니다! 제가 생성한 도메인은 자신의 역할을 잘 수행합니다!그러나 노트는 숫자라면 무엇이든 잘 기록할 수 있습니다! 그게 꼭 주사위의 숫자가 아니어도 상관이 없습니다.그렇기에, 우리는 맥락(컨텍스트)이 필요한 것입니다. 도메인을 연결하여 의미가 있는 역할을 수행하게 하는 것이죠!그렇게 저는 딜러(Dealer)라는 새로운 객체를 만들었습니다! 요청을 받아 주사위를 굴리는 게 게임 같았거든요..!public class Dealer { private final Dice dice; private final Note note; private Dealer(Dice dice, Note note) { this.dice = dice; this.note = note; } public static Dealer playWith(Dice dice, Note note) { return new Dealer(dice, note); } public void rollDiceMultipleTimes(int numberOfRoll) { for (int i=0; i<numberOfRoll; i++) { note.record(dice.throwDice()); } } public void tellTheResult() { note.printTheResult(); } }딜러의 역할은 게임의 진행입니다! 사용자에게 요청 받은 숫자만큼 주사위를 굴려주고! 노트에 결과를 전달하고 기록된 결과를 사용자에게 알려주는 역할을 수행합니다! 😃주사위와 노트는 딜러의 게임 진행이라는 맥락(컨텍스트) 아래에서 자신들의 역할을 수행합니다! 어떤가요? 객체들이 서로 협업 하며 역할을 잘 수행하여 로직을 수행하고 있습니다!또한, 흥미로운 점은 딜러는 주사위와 노트가 자신의 역할만 잘 수행할 수 있다면(인터페이스를 충실히 구현했다면) 얼마든지 다른 주사위나 노트로 바꿀 수 있습니다! 사기를 칠 지도 모르겠군요! 😜 💡정리하며...자, 이제 클린코딩을 수행한 코드를 다시 보겠습니다! 현재의 내부 구현은 모두 알지만, 구현체인 주사위와 노트는 언제든지 바뀔 수 있습니다!그러나, 우리는 주사위와 노트가 자신의 역할만 잘 수행할 수 있다면, 그것이 바뀌어도 상관이 없다는 사실도 알고 있습니다!이것이 객체 지향이 주는 다형성이라는 장점입니다! 글이 너무 길어져서 짧게 설명하는 점 죄송합니다...😭public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); Dice luckyDice = UnknownDice.decideFaces(6); Note memoPad = new MemoPad(); Dealer dealer = Dealer.playWith(luckyDice, memoPad); System.out.print("숫자를 입력하세요 : "); dealer.rollDiceMultipleTimes(scanner.nextInt()); dealer.tellTheResult(); } }객체 지향 정말 매력적이지 않은가요? 책을 통해 이론으로만 배운 객체 지향을 직접 설계부터 구현하며 쓴 저의 긴 기록을 지금까지 읽어주셔서 감사드리며, 객체 지향을 모르시던 분들께 조금이라도 도움이 되었으면 합니다!사실.. SOILD부터 대뜸 외우라고 하면, 어렵습니다 객체 지향..남은 스터디 기간도 다들 즐거운 코딩하시길 바라겠습니다! 🙇‍♂️

백엔드객체지향클린코딩스프링부트인프런워밍업클럽스터디도메인컨텍스트추상화캡슐화

윤대

[도서 정리] - 결합도와 응집도 - { 오브젝트 : 코드로 이해하는 객체지향 설계 }

결합도 : 의존성의 정도, 다른 모듈에 대해 얼마나 많은 지식을 가지고 있는 지를 나타내는 척도.'결합도가 높다'는 두 가지 의미로 해석 될 수 있다.A라는 모듈이 B 모듈의 내부 구현을 자세히 알고 있어, B의 작은 변경에도 A까지 변경해야 할 경우.A라는 모듈을 B, C, D, E 등 다수의 모듈이 의존하고 있어. A를 변경할 시 나머지 모듈도 함께 변경해야 할 경우.즉, '결합도가 낮다'라고 것은 단순히 의존하는 모듈이 적은 것이 아니다. 변경이 일어날 수 있는 부분을 모두 철저히 캡슐화하여, 내부 구현 변경에 의하여 의존하는 다른 모듈이 영향을 받지 않도록 억제 하는 것이다.응집도 : 모듈 내부 요소들이 서로 연관돼 있는 정도.'응집도가 낮다'면 다음과 같은 특성이 나타난다.클래스 변경되는 이유가 두 가지 이상이다.클래스의 인스턴스를 초기화하는 시점에 경우에 따라 다른 속성들을 초기화하고 있다.메서드 그룹이 속성 그룹을 사용하는 여부가 갈린다.위의 3 경우는 해당 클래스의 응집도가 낮다는 지표임으로, 위의 증상이 나타난다면 클래스를 분리할 것을 고려해야 한다. ✒ 정리결국, 모든 것은 변경과 관련되어 있다. 변경이 일어날 수 있는 부분을 추상화하여 구현을 감추고 객체가 인터페이스에만 의존하게 한다면 자연스레 결합도가 낮아진다.서로 다른 속성을 써서 작동하는 비슷한 메소드를 캡슐화하여 새로운 객체로 추출하면, 자연스레 응집도가 높아지게 된다.그렇기에 우리는 적절하게 도메인을 뽑아낸 뒤, 협력에서 책임을 찾고 이를 적절하게 분배해야 할 것이다. 그리고 구현을 하며, 끊임 없이 리팩토링을 한다면 객체지향이 잘 지켜진 코드를 얻을 수 있을 것이다.

백엔드결합도응집도객체지향OOP

진영준

[인프런 워밍업 클럽 스터디 0기 발자국] 2주차 회고

안녕하세요. 주니어 백엔드 개발자를 꿈꾸는 12hugs 실명은 진영준입니다. 😉지난주 월요일부터 인프런 워밍업 클럽 스터디 0기를 시작했으며,2주차에는 무엇을 느꼈고 무엇을 공부했으며 어떤 사실을 깨달았는 지에 대해공유를 해볼까합니다. 그럼 시작합니다!내가 알던 JPA는 더욱 넓은 세계였다.제가 알던 JPA는 단순히 백엔드 개발자가 SQL언어에 대한 공부를 따로 해야하기도 하고,좀 귀찮기때문에 나온 개념이라고 생각했습니다.그래서 별 거 아닌 존재라고 생각하기도 했고, 간과한 부분이 없지 않아있었습니다.그렇지만, 강의를 들으면서 JPA의 기능에는 놀라운 기능들이 있다는 것을 알게되었습니다.existBy, countBy 등등 많은 기능을 지원하기도 하고, 직접 @Query 어노테이션을 통해JPQL언어로 DB에 SQL을 날릴 수 있는 것도 확인하였습니다. 그리고 하이버네이트란 무엇이고, JPA와 ORM은 무엇인지에 대한 개념도 잡히게 되었습니다.아무래도 너무 야생형으로 공부한 입장으로 해당 기능과 관련된 지식이 없으면구글링조차 할 수도 없기때문에 해당 단어들과 기능들은 사막의 오아시스와도 같았습니다. 객체지향 모두 지향하지만, 사실 지양하고 있다.객체지향이 중요하다는 점은 모르는 사람이 없을 것입니다.사실 이런 개념때문에 객체지향언어들이 각광을 받기도 합니다.하지만, 저는 전혀 객체지향을 하고 있지 않았습니다. 제가 짠 로직들은 전부 절차지향이었으며,class가 주인이 되는 코드를 짜왔습니다. 그렇지만, 이번 2주차를 통해 객체지향에 대한 개념이 조금 잡히기 시작했습니다.이건 미니프로젝트를 진행하며, 느낀 부분이었습니다.저는 원래 평소와 같이 서비스에 모든 비즈니스 로직을 쑤셔넣었습니다.하지만, 제가 쓴 코드인데도 불구하고, 읽기가 힘들고, 이해하기가 힘들었습니다.다시 말하자면, 코드싸개였고, 전혀 객체지향적이지도 못했습니다.출처 : https://namu.wiki/w/%EC%BD%94%EB%8D%94 그렇지만, 객체지향을 공부하기 시작하면서 객체의 불변성을 유지하기 위해서기존 테이블 @Entity 객체의 @Setter을 빼고, 정말 객체끼리 상호작용 및 의사소통을 하며,비즈니스 로직의 간소화를 진행할 수도 있었고, 훨씬 깔끔해진 코드와 함께 가독성 또한 좋아지게 되었습니다. 그래서 2주차를 통해 얻게 된 것은?프로젝트를 진행하기 전에 요구사항과 설계가 중요했다는 점을 강조하고 싶습니다.요구사항 스펙은 사람들이 원하는 기능을 함축해놓은 스펙입니다.즉, 클라이언트가 원하는 기능이 없다면, 개발자는 필요가 없어지게 되겠죠. 그리고 설계가 굉장히 중요합니다.설계를 잘 해놓고 시작해야 변수사항에 대해 잘 대처를 할 수 있으며,보다 유연하고, 객체지향적인 코드를 짤 수 있다는 생각을 했습니다. 그래서 저는 처음에 설계를 안하고 미니프로젝트를 시작했기 때문에며칠뒤 코드를 처음부터 다시 짜는 불상사를 일으켰습니다. 더욱 유연하고 뛰어난 개발자가 되고 싶다면,공부도 물론 중요하겠지만, 설계와 요구사항을 충분히 이해하고객체지향적으로 코드를 짤 줄 아는 개발자여야 한다는 걸 깨닫게 된 2주차였습니다.

인프런객체지향절차지향설계워밍업클럽스터디0기

스프링 핵심원리 기본편(김영한) 1 - 객체지향 DIP와 스프링 DI, IoC

  객체는 객체와 끊임없이 상호작용한다. 그렇기에 유연한 변경이 가능해야한다. 예를 들어, 자동차라는 상위 클래스를 다양한 자동차 브랜드로 구현될 수 있고, 운전자가 변화해도 자동차는 영향을 받지 않는다. 사용자, 주문, 할인 등 여러 독립적인 특징을 가진 기능은 클래스로 분리하여 각 클래스에서만 수정 및 사용한다.   역할과 구현을 분리 - 인터페이스와 콘크리트 클래스 인터페이스는 안정적이게, 확장이 무한대로 가능하게 설계해야한다.   SOLID 객체지향 설계 원칙 1. SRP 단일책임원칙 - 변경이 용이한 단위적 책임인가2. OCP 개방폐쇄원칙 - 코드의 변경 없이 확장이 가능한가(조립만으로 변경)3. LSP 리스코프 치환 원칙 - 하위 클래스는 인터페이스(상위 클래스)를 위반하지 않아야한다4. ISP 인터페이스 분리 원칙 - 여러 개의 인터페이스를 통해 명확한 기능을 갖고 있고, 대체 가능성이 높은 환경을 구현할 것5. DIP 의존관계 역전 원칙 - 추상화에 의존할 것, 인터페이스(역할)가 중심이 되어야한다. 구현체에 의존하면 다형성을 잃는다(재활용성을 잃는다) 스프링 컨테이너에 객체 지향 적용 객체를 생성하는 역할과 객체를 실행하는 역할을 분리.의존은 인터페이스로 하고, 설정 파일을 통해 구체적인 구현체를 의존 주입구현체 변경 시 설정 파일만 변경하면 된다.(조립)=> 제어의 역전; 어떤 구현체를 사용할 것인지 AppConfig(Spring)가 결정한다. 동적인 인스턴스 의존관계    

객체지향javaSOLIDspringDIIoCDIP강의김영한

객체 지향 프로그래밍 입문(최범균) 2 - 다형성, 추상화, 조립

  다형성이란, 여러 모형으로 변화하는 것이다. 하나의 객체가 여러 타입을 갖는 것이다. 추상화란, 특정한 성질(interface) 또는 공통 성질(abstract, 일반화)을 뽑아내는 과정이다. 추상화를 통해 객체는 다형적인 모형을 변화 가능하다   <추상화 시점> 추상화는 의존 대상이 변경하는 시점에 추가한다. 실제 변경 및 확장이 일어날 때 공통점을 파악하고 뽑아낸다.   <추상화 예시> 클라우드 파일 관리 기능이 있고, 대상 클라우드의 종류가 n가지일 경우.클라우드 종류에 따라 if문으로 분기하는 로직이 아닌 공통기능인 클라우드 파일 시스템을 추상화한다.클라우드 파일 시스템에서는 파일 목록과 관련된 CRUD 기능을 추상화하고,클라우드 파일에서는 개별 파일의 CRUD 기능을 추상화한다. 특정 클라우드 구현체에서는 추상 클래스를 상속받아서 기능을 재정의한다. 추상화가 진행되면, 구현 클래스의 변경은 있더라도(조립) 서비스 로직은 바뀌지 않는다.   <상속보다는 조립> 상속을 통해서 재사용을 하게 된다면,1. 상위 클래스의 변경이 어렵고2. 기능과 확장이 필요한 만큼 클래스가 증가하고3. 상속을 오용하게 된다.(비슷한 메서드 착오) 상속은 하위타입일 경우에 진행하고, 보통의 경우 객체를 참조하는 방식으로 진행할 것.    

java객체지향최범균강의추상화다형성조립객체참조

객체 지향 프로그래밍 입문(최범균) 3 - 분리, 의존 주입, DIP

<역할과 기능 분리 방법> 1. 패턴 적용 전형적 분리(아키텍처, 디자인패턴) 2. 계산 분리 로직의 기능화 3. 연동 분리 클래스 분리 4. 연속적인 if-else는 추상화 고민할 것   적절한 역할 분리는 테스트도 용이하게 한다.사용자와 직접적으로 관련된 기능은 내부 메서드로, 간접적으로 관련있는 기능은 별도의 클래스로 분리한다.   <의존> 순환 의존은 변경이 연쇄적으로 전파된다. 기능 변경의 파장이 커지면 안 좋기 때문에 의존은 적을수록 좋다. 의존대상의 기능이 많은 경우 클래스로 분리하거나 단일 기능으로 묶을 수 있는지 확인하라. 예를 들어 민원팩토리, 민원리포지토리를 민원등록으로 묶기   <스프링 의존 주입> 추상적 인터페이스를 의존하고, 의존 주입은 보통 생성자 방식으로 외부(스프링)에서 진행한다. 내부에서 new()로 생성하는 것과 반대이다. 1. 의존 대상이 바뀌면 그 대상을 조립하는 부분만 수정하면 됨 2. 대역 객체를 통해 테스트가 가능하다   <DIP 의존 역전 원칙> 고수준 모듈(기대수준), 저수준 모듈(단위적 실제 행위) 고수준 모듈을 의존해야한다. 반대로 고수준 모듈이 저수준 모듈을 의존하는 경우, 저수준 모듈이 변화할 때 고수준 모듈에 영향을 끼침 (목표를 향해 개발하는 것이 아닌, 개발에 따라 목표가 변하는 현상)고수준 모듈을 구현한 추상타입(인터페이스)을 저수준 모듈이 의존하는 방식을 추구해야한다.    

java강의최범균DIPDIinterface분리객체지향

객체 지향 프로그래밍 입문(최범균) 1 - 객체지향, 캡슐화

좋은 코드란, 낮은 비용으로 변화할 수 있는 코드이다 이것은 1. 캡슐화 2. 추상화(다형성 지향)로 이루어낼 수 있다.   절차지향적 코드는 진행될수록 여러 조건문으로 복잡해질 수 있다. 객체지향적 코드는 객체가 제공하는 기능(메서드)이 중심이 되어 설계하는 것이다.  - 호출, 리턴, 익셉션 등의 메세지의 교환 - 데이터 클래스(VO, DTO)는 객체가 아니다. 객체의 기능이 없이 값에만 접근하기 때문이다.   캡슐화는 데이터와 관련된 기능을 묶는 것이다. 데이터의 상세 내용을 외부에 감추고, 외부와 무관하게 객체 내부의 구현 변경이 가능하다. 객체의 기능을 비즈니스 로직이 아닌 객체 내부의 메서드로 구현하면, 기능에 변화가 요구될 때 해당하는 내부 기능을 변경하면 캡슐화를 사용한 곳에 별도의 수정이 필요하지 않다.   캡슐화의 규칙 1. 데이터를 요구하는 것이 아닌 데이터의 처리를 요구할 것if(member.getAge() > 19) Xif(member.isAdult()) O 2. 메서드에서 생성한 객체의 메서드만 호출할 것파라미터로 받은 객체의 메서드만 호출할 것필드로 참조하는 객체의 메서드만 호출할 것 >> 연속적인 메서드 호출이 아닌 객체에 있는 하나의 메서드로 처리member.isAdult() + member.isVIP() + member.addCoupon()으로 하나씩 처리하는 것보다member.receiveBenefits()로 위 세 개 기능 묶기     객체는 속성과 기능으로 구성되어있다. 객체의 여러 기능을 참조하고 묶어서 새로운 기능에 사용하는 것은 객체 지향적인 방식이다.        

java객체지향최범균강의캡슐화DDD

<도서정리> 객체지향의 사실과 오해

객체지향이란. 흔히 객체지향을 세상을 객체들의 모임으로 보고, 객체들이 상호작용하는 것을 소프트웨어 세계에 모방하는 방식으로 소개한다. 하지만, 객체지향은 실세계를 모방하는 것이 아닌 새로운 세계를 창조하는 것이다. 현실 속에서 수동적인 존재가 소프트웨어 객체로서는 능동적인 객체가 된다. 사물의 의인화가 이루어지며, 얼마든지 필요한 능력을 가질 수 있다. 객체 상태와 행동의 명명 또한 창조의 영역이다.   객체란. 객체들 간에는 특정한 목표를 위해 협력하며, 객체는 협력 속에서 맡은 역할에 책임을 진다. 협력은 연쇄적인 요청과 응답으로 구성되어있다. 객체 특징재활용성 - 여러 객체가 동일한 역할을 수행할 수 있다.활용성 - 역할을 대체가능성을 의미한다.다형성 - 책임을 수행하는 방법은 자율적으로 선택할 수 있으며, 다양한 방식으로 요청 수행이 가능하다.한 객체가 동시에 여러 가지 역할을 수행할 수 있다. 다양한 곳에 참여한다.(참조되어 사용된다)   협력. 시너지; 전체는 부분의 합보다 크다. 성공적인 협력을 위해서는 적절한 단위적인 책임을 부여하는 것이 중요하다.  객체는 충분히 협력적이어야한다. 다른 객체에게 적극적으로 도움을 요청할 정도로 열린 마음을 지녀야 하며, 모든 것을 스스로 해결하려는 전지전능한 객체는 복잡함에 의해 자멸한다. 객체는 자율성을 가진다.   객체의 자율성. 캡슐화 - 객체의 자율성은 객체의 내부와 외부를 명확하게 구분하는 것으로부터 나온다. 객체의 사적인 부분은 객체 스스로 관리하고, 외부에서 일체 간섭할 수 없도록 차단해야한다. 객체의 외부에서는 접근이 허락된 수단을 통해서만 객체와 의사소통해야한다. 무엇을 수행하는지는 알 수 있지만 어떻게 수행하는지에 대해서는 알 수 없다. 객체는 상태와 행동을 지닌다.  객체는 자신의 상태를 직접관리하고 상태를 기반으로 스스로 판단하고 행동하는 자율적인 존재이다. 객체의 행동이 상태를 결정한다. 객체의 행동은 객체가 협력에 참여하는 방법이며, 객체의 적합성은 객체의 행동으로부터 결정된다. 책임주도설계 - 객체가 어떤 책임을 갖는가가 설계를 주도한다. interface를 통해 제공가능한 정보와 서비스를 알려주는 동시에 캡슐화를 수행할 수 있다 인터페이스가 변경되지 않는다면, 내부 방식을 변경하더라도 그것이 영향을 끼치지 않는다. 동일한 인터페이스에 의존한다면, 어떠한 구현체와도 상호작용을 할 수 있다.   객체와 추상화. 추상화를 통해 현실세계의 복잡성을 극복할 수 있으며, 그를 통해 사물의 본질에 접근할 수 있다. 추상화 과정 - 유사성, 공통점을 통해 분류한다. 객체의 추상화는 분류(classification)를 통해 이루어진다. 객체지향은 객체를 지향하는 것이지 클래스를 지향하는 것이 아니다 일반화/특수화 서브타입은 슈퍼타입(본질)을 대체할 수 있어야한다. 슈퍼타입의 행동은 서브타입에 자동으로 상속된다. 타입 타입은 추상화이다. 타입은 동적인 상태 변경을 단순화하는 정적 객체 특징에 집중한다. 클래스는 타입을 구현하는 도구이다. 추상화를 통해 다양한 객체들이 조립되어 역할을 수행할 수 있다면 협력이 유연해지며 객체들의 재사용성이 높아진다.   메세징 메세징(요청)은 객체에게 접근할 수 있는 유일한 방법이다. 어떻게 할지는 객체 스스로가 결정하며, 메세지로는 무엇을 할지만을 요청한다. 요청을 받은 후 객체는 적절한 메서드를 선택하여(다형성) 요청을 수행할 것이다.  객체지향은 객체들이 주고받는 메세지들로 구성된다. 클래스는 객체들의 속성과 행위를 담는 틀일 뿐이며, 객체의 속성과 행위가 중심이 되어야한다. 또한 객체지향은 객체를 넘어서 객체들 간의 커뮤니케이션에 초점을 맞출 때 이루어진다. 메세징을 이용한 객체지향 객체가 책임을 완수하기 위해, 다른 객체의 도움이 필요하다고 판단되면도움 요청 메세지를 결정한다. 메세지를 결정한 후 메세지를 수행하기에 적합한 객체를 선택한다. -> 메세지가 수신자의 책임을 결정한다.   

도서객체지향협력역할책임추상화다형성캡슐화