ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 객체지향과 디자인패턴 2
    언어/객체지향 2023. 8. 13. 14:09

     

    1.1  절차지향 

     

    - 데이터를 조작하는 코드를 별도로 분리해서 함수나 프로시저와 같은 형태로 만듦

    -  각 프로시저들이 데이터를 조작하는 방식 

    -  순서에 따르는 것이 아니라, 프로시저에 따른 프로그래밍이다.

     

    ex) 시험 성적 관리 프로그램 

           - 평균 계산, 화면출력 등의 프로시저가 존재할 것이고 각 프로시저는 데이터를 공유할 것이다.

           - 이 과정에서 절차지향적 프로그래밍은 데이터를 중심으로 표현하게 된다.

     

    - 절차지향의 문재 

       > 데이터 타입이나 의미 변경시 수정해야하는 프로시저가 증가

       > 같은 데이터를 프로시저들이 서로 다른 의미로 사용하는 경우가 많다.

       > 절차지향의 전형적인 문제는 한 곳을 수정하면 다른 여러 곳에서 문제가 발생하는 것

     

    1.2 객체지향

     

      - 데이터와 그와 관련된 프로시저를 객체라는 단위로 묶는다.

      - 객체는 프로시저를 실행하는데 필요한 만큼의 데이터를 가진다. -> 객체가 모여 프로그램을 구성

      - 각 객체들은 서로 연결되어 다른 객체가 제공하는 기능 사용

      - 객체는 다른 객체에 기능을 제공하기 위해 프로시저를 사용함 -> 이때 프로시저는 자신이 속헌 객체의 데이터만 접근할 수 있으며, 다른 객체의 데이터는 접근할 수 없다.

      - 모든 프로시저가 데이터를 공유하는 절차지향과 다르게 객체지향은 객체별 데이터와 프로시저가 정의되어 있다.

      - 따라서 요구사항 변경시 해당 객체만 수정하면 되므로 쉽게 변경할 수 있는 장점이 있다.

     

     

    2. 객체 

     

    2.1 객체의 핵심은 기능 제공 

     

     - 객체에는 상태와 행동이 정의되어 있지만, 이는 물리적 특징일 뿐 객체를 결정하는 것은 객체의 책임 

        즉 어떤 기능을 제공하느냐이다.

     

    2.2 인터페이스와 클래스 

     

    - 객체가 제공하는 기능을 오퍼레이션이라고도 함 

    -  오퍼레이션을 사용하기 위한 사용법 시그니처는 이름,파라미터 및 파라미터 타입(매개변수), 리턴 값으로 구성됨

    -  한 객체가 제공하는 모든 오퍼레이션의 집합을 객체의 인터페이스라고 한다. 서로 다른 인터페이스를 구분할 때 사용하는 명칭이 타입이다. (언어에서 제공하는 인터페이스 뜻 하는 것이 아니다.)

    -  인터페이스는 객체가 제공하는 기능 명세 -> 실제 객체 구현 정의는 클래스를 통해 할 수 있다.  

     

    * 언어에서 제공하는 interface타입은 개념상의 인터페이스를 더 잘 반영하도록 제공해주는 타입임 

     

    2.3 메시지

     

    - 오퍼레이션 실행 요청을 메시지라 한다. (단일 객체의 책임이 아닌, 여러 객체 사이의 관계로서 책임)  [1책임 다메시지]

     

    2.4 객체의 책임과 크기 

     

    - 객체는 객체가 제공하는 기능으로 정의 -> 객체마다 자신의 책임이 있음 

    - 한 객체가 가지는 책임을 정의한 것이 타입/인터페이스라 할 수 있다. 

    - 객체의 책임이 많아지면 -> 절차지향적으로 코딩할 가능성이 커진다. -> 책임의 크기는 작을수록 좋다.(단일책임원칙)

    - 책임을 갖는 다는 것은 객체가 역할을 수행한다는 의미를 갖는다. 역할은 곧 책임과 동일한 의미이다.

     

    3. 의존 

     

    - 객체가 다른 객체를 생성하거나, 다른 객체의 메서드를 호출할 때, 매개변수로 전달받을 때 의존한다고 표현한다.

    -  의존의 문제점은 의존타입에 변경이 발생할 때 함께 변경될 가능성이 높다는 것이다. (순환 의존 문제) 

     

    public class FlowController{
    
    
    	public void process(){
        	FileDataReader reader = new FileDataReader(filename);//객체생성
            byte[] plainBytes = reader.read();// 메서드 호출 
            
            ByteEncryptor encryptor = new ByteEncryptor();
            byte[] encryptedBytes = encryptor.encrypt(plainBytes);
            
            FileDataWriter writer = new FileDataWriter();
            writer.write(encryptoedBytes);
        
        
        }
    
    }

     

    3.1 의존의 양면성

     

    public class Authenticator{
    	public boolean authenticate(String id, String password){
        	Member m = findMemberByid(id);
            if( m == null) return false;   
            return m.equalPassword(password)
        }
    }
    
    
    public class AuthenticationHandler{
    
    		public void handleRequest(String inputid,String inputpass){
            
            Authenticator auth = new Authenticator(); // 의존 
            
            if(auth.authenticate(inputid,inputpass){
            	//아이디 암호 일치
            }else{
            	//일치 x
            }
            
            }
    }

    - 위 코드에서 AuthenticationHandler와 Authenticator 사이의 의존 관계가 있다. 

    - 이 상황에서 잘못된 아이디를 입력한 것이니지 아니면, 암호가 틀린 것인지 확인하기 위해 시스템 상에 로그를 남겨달라는 요구가 추가 되었다면, 기존 Authenticator의 authenticate()메서드는 boolean값을 리턴하는 것이 아니라, 아이디가 잘못된 건지, 암호가 잘못된 건지 알려줄 수 있어야한다. 

     

    public class Authenticator{
    
    	public void authenticate(String id, String pass){
        	Member m = findMemberByid(id);
            if(m == null) throw new MemberNotFoundException();
        	
            return (!m.equalsPassword(password)) throw new invalidPasswordException();
        }
    
    }

    - 만약 Authenticator가 요구사항에 맞게  이런식으로 변화한다면, 이와 의존관계를 가지는 다른 코드들도 변화를 겪게 될 것이다.

     

    > 내가 변경되면 나에게 의존하는 코드에 영향을 준다.

    > 내 요구가 변경되면, 내가 의존하는 타입에 영향을 준다.

     

    4. 캡슐화 

     

    - 객체지향의 장점은 한 곳의 변경이 다른 곳에 영향을 주지 않게 하는 것 -> 이를 가능하게 해주는 것이 캡슐화

    - 객체의 내부 기능 구현을 감추는 것 의미 -> 기능 구현이 변경되더라도 기능을 사용하는 코드는 영향받지 않도록 하여 내부 구현 변경의 유연함을 주는 기법 

     

    4.1 캡슐화를 위한 두 개의 규칙 

     

    - tell, don't ask (기능 실행을 요청하는 방식으로 최대한 코딩하자) 

    - 데미테르의 법칙 (어떤 상황이던 객체의 메서드만 호출하라는 것)  * 객체에 대한 메서드 호출은 한번만 하자 

    if(member.getExpiryDate() != null && membergetExpiryDaye().getDate() //)
    // 데이터를 직접가져와서 직접 여러 조건을 검사 -> 절차지향적 방식이다
    if(member.getDate().getTime() )//..  데미테르 법칙 위반

    5. 객체 지향 설계 과정 

     

    - 책임,의존,캡슐화 -> 객체 지향 설계란 다음을 반복하는 과정

     

    1. 제공해야 할 기능을 찾고 또는 세분화하고, 기능을 알맞은 객체에게 할당한다.

        1.1 기능을 구현하는데 필요한 데이터 추가

        1.2 기능은 최대한 캡슐화한다.

    2. 객체간 어떻게 메시지를 주고받을 지 결정한다.

    3. 1,2를 반복 

     

    협동을 생각해보자 

    파일 데이터 암호화 (원본 파일 읽어서 암호화 한 뒤에 새로운 파일에 결과를 저장) 

    필요기능

    - 데이터 읽기, 암호화 하기, 데이터 쓰기 

     

    > 기능을 찾으면, 기능을 제공할 객체 후보를 찾고, 객체가 어떻게 연결되는지 그려보자 

    > 이 과정에서 객체가 기능을 제공할 때 사용할 인터페이스가 도출된다(책임과 메시지) 

    >  이제 각 책임에 맞게 구현해주면된다.

     

    - 객체의 크기는 한번에 완성되는 것이 아니라 구현하다보면, 명확해짐 구현 과정에서 점차 책임이 세분화 될 것이다.

    - 객체지향 설계는 개발과 설계가 동시에 진행됨 따라서 변경되는 부분을 고려하여 유연한 구조를 갖도록 노력하자 

    - 변경의 유연함은 추상화를 통해 얻을 수 있다. 

Designed by Tistory.