티스토리 뷰

728x90

 

객체지향 프로그래밍의 기본 원칙은 캡슐화(encapsulation), 상속(inheritance), 다형성(polymorphism)이며, 이들은 소프트웨어를 보다 모듈화하고 유지보수하기 쉽게 한다.

  1. 캡슐화(Encapsulation):
    • 캡슐화는 관련된 데이터와 메서드를 하나의 단위로 묶는 것
    • 클래스는 데이터(속성)와 해당 데이터를 다루는 메서드(함수)를 함께 캡슐화하여 객체를 형성
    • 캡슐화는 정보 은닉(Information Hiding)을 통해 객체의 내부 구현을 외부로부터 숨기고, 외부에서는 객체의 인터페이스를 통해 상호작용한다.
  2. 상속(Inheritance):
    • 상속은 기존의 클래스에서 정의된 속성과 메서드를 새로운 클래스에서 재사용할 수 있도록 하는 개념
    • 상속을 통해 코드 중복을 줄이고, 기존 클래스의 기능을 확장하거나 변경할 수 있다.
    • 부모 클래스와 자식 클래스 간의 계층 구조를 형성하여 객체 간의 관계를 표현
  3. 다형성(Polymorphism):
    • 다형성은 같은 이름의 메서드나 연산자가 다양한 상황에서 다르게 동작할 수 있는 능력을 의미합니다.
    • 다형성은 오버로딩(Overloading)과 오버라이딩(Overriding)을 통해 구현
    • 오버로딩은 같은 이름의 메서드가 매개변수의 타입이나 개수에 따라 다르게 동작하는 것을 말하며, 오버라이딩은 부모 클래스에서 정의된 메서드를 자식 클래스에서 재정의하여 사용하는 것을 말합니다.

 

그러나 막상 프로그래밍을 하면서 이 3요소를 제대로 지키지 못하는 경우가 많고, 고려하지 못하는 경우가 많다. 

나도 그렇다. 그러다 이번 업무 중 소켓통신을 사용하는 일이 있었고, 회사 처음으로 코드리뷰 시간을 가졌다.

 

나에게 업무를 주신 수석님이 내 코드를 보면서 상속을 사용을 하면 좋을 것 같아요. 라는 말씀을 해주셨다.

넹..? 상속이요..? 머리가 벙쪘다.. 코드를 짜면서 전혀 고려를 해보지 못한 것이기 때문이다.

리뷰 시간에 엇..넵..넵..(이해안간다..🙄) 하고 리뷰가 끝난 다음 다시 살펴보았다.

 

상속화를 고려하지 못한 나의 코드는 아래와 같다.

다른 요청에서 사용할 수 있도록 메세지를 전달하고 응답을 받는 것을 함수화 했고, 어떤 요청이든 저 sendMessage와 recieveMessage를 호출하면 되서 코드의 재사용성을 높혔다고 생각했다! 가장 중요한게 뭔지도 모르고!

 

[상속을 고려하지 못한 코드]

public class SocketConnector {
    public MessageResponse request(MessageRequest messageRequest) {
        try(Socket socket = new Socket()) {
            //소켓 타임아웃 설정
            socket.connect(socketAddress, SOCKET_TIME_OUT);
            //소켓 read timeout 설정
            socket.setSoTimeout(SOCKET_TIME_OUT);
            //메세지 전달
            sendMessage(MessageType.Type.getValue(), MessageRequest);
            //메세지 응답 및 리턴
            return (MessageResponse) receiveMessage(MessageResponse.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     *  응답메세지 받기
     * @param returnType
     * @throws Exception
     */
    private Object receiveMessage(Class<?> returnType) throws Exception {
        //메세지 응답 코드
        return returnType;
    }

    /**
     * 요청 메세지 보내기
     * @param messageType
     * @param obj
     * @throws Exception
     */
    private void sendMessage(String messageType, Object obj) throws Exception {
        //메세지 전달 코드
    }
}

 

[상속을 고려한 코드]

socket 객체를 상속받아, 객체를 새롭게 생성하지 않고, 부모 클래스에 정의된 함수들을 그대로 사용 할 수 있었다. 

public class SocketConnector extends Socket{

    public MessageResponse request(MessageRequest messageRequest) {

        try  {
            //소켓 타임아웃 설정
            connect(socketAddress, SOCKET_TIME_OUT);
            //소켓 read timeout
            setSoTimeout(SOCKET_TIME_OUT);
            //메세지 전달
            sendMessage(MessageType.Type.getValue(), MessageRequest);
            //메세지 응답 및 리턴
            return (MessageResponse) receiveMessage(MessageResponse.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

 

사실 두 코드가 크게 차이가 없어보이지만, 상속 받지 않은 경우에는 request1, request2, request3 과 같이 새로운 요청들이 생긴 경우, 각각의 요청 안에서 매번 소켓 객체를 새로 만들어야한다. 그렇지만 상속을 사용하는 경우 이런 불필요한 과정이 없어진다! 완전 짱임.. 이렇게 개념적으로만 알고 있던 걸 실무에서 사용해볼 때 너무나 재밌는 것 같다😆

 

앞으로도 프로그래밍을 하면서 상속을 통해 코드를 재사용할 수 있는지 고려해보도록 해야겠다!

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함