인터페이스.. 추상클래스.. 무슨 차이지(2024.04.09)

YJ·2024년 4월 11일
post-thumbnail

블로그 작성법
목표 > 공부한 내용 > 얻었고, 앞으로 이걸 해봐야지 적기

수업 목표

  • 인터페이스와 추상클래스의 차이를 알자

공부한 내용

interface EX01 {
	public abstract void method1();
    public abstract void method2();
}

인터페이스와 추상클래스

인터페이스

User Interface

cf. CLI vs GUI

GUI(Graphic User Interface)
: 그래픽으로 인터페이스를 제공

vs

CLI(Command Line Interface)
: 명령어로 인터페이스를 제공

shell
: 쉘(Shell)은 리눅스의 핵심인 커널과 사용자를 연결해주는 인터페이스 역할

git bash
: GNU 프로젝트를 위해 브라이언폭스가 작성한 유닉스 쉘

windows cmd
: 운영체제 위에 응용프로그램들 관리까지 해줌

현업에서 주로 CLI를 사용하는 이유?

GUI의 버튼에 CLI의 모든 기능이 다 담겨 있을까?
예를 들어, Git에서 GUI의 Commit 버튼에는 commit과 add 기능이 한 번에 담겨 있다.
CLI는 내가 자유롭게 옵션값을 사용할 수 있어서, 내 입맛대로 기능을 다룰 수 있다. 그러나, GUI는 기능에 한계가 있고 구현되지 않은 것들도 많다.
따라서, CLI를 사용하는 경우가 많다.

인터페이스의 목적

안에 뭐가 있는지 몰라도, 기능을 사용하기 위함

위 그림에서 보면, 우리는 B만 알고 그 안에 상세한 기능까지 우리가 사용하기에 알 필요가 없다.

추상클래스

상위 버전에 공통된 기능을 담고, 해당 기능을 구현하여 사용하자.

근데,, (오늘 배운 제일 중요한 내용)

그림으로만 봤을 때는 추상클래스에서는 내부적인 기능을 가릴 수 없을까?
그리고, 인터페이스는 공통 규약을 안 내려주나?

그러면, 다음과 같은 질문을 할 수 있다.
1. 이 자리에 추상클래스가 아니라 인터페이스를 위치 시키면 안되나?
2. 이 자리에 인터페이스가 아니라 추상클래스를 위치 시키면 안되나?

Q1. 추상 클래스는 아래 구현체를 가려주지 않는지 인터페이스는 공통 규약을 내려주지 않는지

A1. 둘 다 된다.
객체지향과 절차지향을 생각하자.
객체지향도 객체를 먼저 생각할 뿐이지, 뒷단의 순서를 생각한다.
절차지향도 객체로 생각해서 구현할 수 있다.

Q2. 둘 다 JDK 22까지 살아 있는 이유가 뭔지
A2. 목적의 차이이다.
추상클래스는 공통 규약 이 목적이다.
인터페이스는 아래 구현체를 가려주는 역할 이 목적이다.

회사에 가보면, 주로 인터페이스를 많이 사용한다.
왜 그럴까?
구현하는 입장에서 생각해보면 인터페이스가 자유도가 더 높다.
그래서 인터페이스를 많이 사용하곤 한다.

궁금한점

  1. 인터페이스를 상속할 수 있을까?
interface Car{
	void drive();
}

interface Tesla extends Car{
	void autoDrive();
}

A. 가능하다. 인터페이스를 상속하면 하위 인터페이스를 구현한 클래스에서는 상위 인터페이스의 메서드도 사용할 수 있다.

다형성이란?

  1. 하나의 타입에 여러 가지 객체를 담을 수 있다.
  2. 하나의 객체를 여러 가지 타입에 담을 수 있다.

오늘 하루 중에 생각해보자.
일단은 2번 같다.

interface Car{
	void drive();
}

interface Tesla extends Car{
	void autoDrive();
}

interface AirPlane {
	void fly();
}

8. 클린코드와 리팩토링

클린코드란

// 1
return hi >= 0 ? joon * hi : joon / -hi;

// 2
if (hi >= 0) {
	return joon * hi;
} else {
	return joon / -hi;
}

1번은 삼항연산자를 사용해 한 줄만에 작성한 코드
2번은 조건문을 사용하여 여러 줄에 작성한 코드

위 둘 중 클린코드는 2번이라고 한다.
왜냐하면, 1번은 사람이 이해하기가 어렵기 때문이다.

  • 클린코드를 뭐라고 생각하는가?
    딱 코드를 읽어보고 뭐하는 코든지 알겠다. 라고 이해가 되면 클린코드이다.

  • 클린코드의 장점
    클린코드는 나 혼자 하는 프로젝트 일 수록 더 중요하다.
    2주전에 짠 코드를 다시 보면 이해가 되는가?
    대부분 잊어 버릴 것이다.

  • 코드 인스펙션
    제품의 품질을 향상시키기 위해 제품을 실 행하지 않고 제품의 소스코드를 확인해 결함을 발견하는 방법

  • 객체 지향, 클린 코드 참 쉽죠? (로버트 C. 마틴)

의도가 분명하게 이름 지을 것

클래스, 메소드, 변수 등을 명명할 경우,
주석으로 설명하기 보다는 코드 자체로 이해가 될 수 있도록 작성하는 것이 좋다.

모호단 단어를 포함하지 말 것

모호한 약어의 접두사/접미사는 사용하지 않는 것이 좋다.
또한, 접미사로 컨테이너가 포함된 이름은 복수단어로 대체하는 것이 좋다.

//public List<String> nameListForUser(Data inputData) throws Exception {
public List<String> namesForUser(Data inputData) throws Exception {
  • 이미 타입을 List로 해놨으므로 변수명에 List를 포함하지 말고, 복수형으로 더 구체적인 이름을 작성하도록 하자.

명령과 조회를 명확히 분리

메소드는 뭔가를 수행하거나 답하거나 하나만 해야한다.
나는 수행을 하고 답을 하고 하나의 메서드에서 두 개의 기능을 작성하면서 사용한 것 같다. 이렇게 작성하면 메서드가 도대체 무엇을 하려고 하는 것인지??? 혼란이 가중된다.

if ( set( name, "서유준") ){
	
}

위 코드를 보자.
위 코드가 name 변수에 값이 있으면 값을 할당하지 말고,
값이 없을때만 값을 할당하여 성공 여부를 판단하는 메서드라면
... set 이라는 이름만 보고 이해가 가능한가?

만약에 위와 같은 기능을 하는 메서드라면,
아래와 같이 구현하자.

if (existName( name ) {
	setName( name, "서유준)
}

메서드는 사용이 될때만 메모리에 올라간다.
그러면, 메소드를 쪼개면 쪼갤 수록 메모리를 효율적으로 사용할 수 있다.
메서드는 한 기능만 담당하고 최대한 쪼개자. 그러면, 언젠가는 내 코드가 문장처럼 보이는 날이 올 것이다.

주석은 나쁜 코드를 보완하지 못함

주석으로 설명을 하기 보다는, 코드로 의도를 전달하도록 노력한다.

9. 자바 컬렉션 API

치명적인 배열

  • 시간복잡도
  • 자료 삭제/삽입 불편

ArrayList

어레이 + 리스트
리스트란 인덱스가 있고, 삽입/수정/삭제가 어디든 가능한 나열/일렬로 된 데이터구조이다.
삭제가 되면, 한칸씩 당겨지고
삽입이 되면, 한칸씩 밀린다.

ArrayList vs LinkedList
이거를 구분하는 것이 중요하다.

제네릭

ArrayList<T> arrayList = new ArrayList<>();

제네릭이란?
클래스 내부에서 사용할 데이터 자료형을 미리 확정하는 것이 아니라,
객체를 생성할 때 확정하는 것이다.

객체가 들어올 때마다, instanceOf로 구분을 하거나
다른 객체를 만들기 위해 여러 클래스를 만들어야 하나
그런 수고를 덜어줄 수 있다.

인터페이스, 추상클래스를 쓰다보면 사용한다.
스프링에서도 제네릭을 사용해서 이미 구현한 코드들을 화려하게 만들어놓은 곳이 있다.

LinkedList

배열이랑 리스트를 비교할 때 사용한다.

데이터 ------> 데이터

3분 스택 / 3분 큐

인터넷 세상에서의 스택과 큐

  • 스택
    웹 브라우저 뒤로가기
    실행 취소 (되돌리기기능)


  • 프린터 출력 처리
    너비 우선 탐색(BFS)
    캐시 구현
    선입선출이 필요한 대기열(캐치테이블, 테이블링 등 웨이팅 서비스)

앞으로 이걸 해봐야지

인터페이스와 추상클래스의 목적에 대해 배운 것 같다.
인터페이스의 목적은 사용자가 인터페이스로 구현된 클래스의 세부적인 기능을 알지 못한다 하더라도 인터페이스만 보고 사용을 할 수 있도록 보안적인 목적을 위함 이다.
추상클래스의 목적은 공통적인 기능을 상위 클래스로 뺌으로써 상위 클래스를 상속받은 하위 클래스들을 공통 기능을 구현할 수 있다.는 것이다.

이것에 대해 추가적으로 공부를 해보았다.

추상클래스 => '복제'를 떠올리자.
인터페이스 => '계약서', '설계도'를 떠올리자.

집을 구현한다고 생각해보자.
추상클래스로는 여러 개의 집을 복제해서 생성한다.
인터페이스는 집을 복제해서 만들때, 문은 개발자가 원하는 것을 만든다고 생각해보자.

추상 클래스로 여러 집들을 복제해서 만들고, 각 집 객체들을 객체에 따라서 수정하는 것에는 인터페이스를 사용하자.

위 집을 추상 클래스로 나타낸 코드이다.
추상 클래스를 통해

abstract class House {
	private String wall = "House wall";
    private String roof = "House roof";
    private Door door;
   
    
    void setDoor(Door door) {
    	this.door = door;
    }
    
    Door getDoor() {
    	return door;
    }
    
    void openDoor() {
    	System.out.println("Basic door opened");
    }
    
    void closeDoor() {
    	System.out.println("Basic door closed");
    }
}

interface Door {
	void openDoor();
    void closeDoor();
}

class BasicHouse extends House {
	
}

class MyHouse extends House {
	@Override
    void openDoor() {
    	getDoor().openDoor();
    }
    
    @Override
    void closeDoor() {
    	getDoor().closeDoor();
    }	
}

class myDoor implements Door {
	@Override
    public void openDoor() {
    	System.out.println("My Door Opened");
    }
    
    @Override
    public void closeDoor() {
    	System.out.println("My Door closed");
    }
}

public class Abstract {
	public static void main(String[] args) {
    	House basicHouse = new BasicHouse();
        
        basicHouse.openDoor();
        basicHouse.closeDoor();
        
        House myHouse = new MyHouse();
        Door myDoor = new myDoor();
        
        myHouse.setDoor(myDoor);
        
        myHouse.openDoor();
        myHouse.closeDoor();
    }
}

이 집을 나타낸 추상 클래스를 상속받아 여러 집들을 구현할 수 있다.

위 코드 구조

참조링크
https://www.youtube.com/watch?v=yQ_WvWm3oKs

profile
dev

0개의 댓글