본문 바로가기
Backend/Java

[김영한 실전 자바 - 기본편] 패키지

by 박상윤 2024. 5. 18.

2024/05/18

패키지 - 시작

쇼핑몰 시스템을 개발한다고 가정, 프로그램이 매우 작고 단순해서 클래스가 몇개 없다면 크게 고민할 거리가 없겠지만, 기능이 점점 추가되어서 프로그램이 아주 커지게 된다면 어떻게 될까?

 

아주 작은 프로그램

Order
User
Product

 

큰 프로그램

User
UserManager
UserHistory
Product
 ProductCatalog
 ProductImage
Order
 OrderService
 OrderHistory
 ShoppingCart
CartItem
Payment
 PaymentHistory
Shipment
 ShipmentTracker

 

매우 많은 클래스가 등장하면서 관련 있는 기능들을 분류하고 관리하고 싶다는 생각이 든다.

 

컴퓨터는 보통 파일을 분류하기 위해 폴더, 디렉토리라는 개념을 제공한다. 자바도 이러한 개념을 제공하는데, 바로 패키지이다.

카테고리로 분류

* user
* User
   * UserManager
   * UserHistory
 * product
   * Product
   * ProductCatalog
   * ProductImage
 * order
   * Order
   * OrderService
   * OrderHistory
 * cart
   * ShoppingCart
   * CartItem
 * payment
* Payment
   * PaymentHistory
 * shipping
   * Shipment
   * ShipmentTracker

 

user, product 등이 바로 패키지이다. 해당 패키지 안에 관련된 자바 클래스들을 넣으면 된다.

패키지(package)는 이름 그대로 물건을 운송하기 위한 포장 용기나 그 포장 묶음을 뜻한다.

 

패키지 사용

패키지를 먼저 만들고 그 다음에 클래스를 만들어야 한다.

패키지 위치에 주의하자

 

pack.Data

package pack;

public class Data {
	public Data() {
    	System.out.println("패키지 pack Data 생성");
    }
}
  • 패키지를 사용하는 경우 항상 코드 첫줄에 package pack과 같이 패키지 이름을 적어주어야 한다.
  • 여기서는 pack 패키지에 Data 클래스를 만들었다.
  • 이후에 Data 인스턴스가 생성되면 생성자를 통해 정보를 출력한다.

pack.a.User

package pack.a;

public class User {
	public User(){
    	System.out.println("패키지 pack.a. 회원 생성");
    }
}
  • pack 하위에 a라는 패키지를 만든다.
  • pack.a 패키지에 User 클래스를 만든다.
  • 이후 User 인스턴스가 생성되면 생성자를 통해 정보를 출력
package pack;

public class PackageMain1 {
	public static void main(String[] args){
    	Data data = new Data();
        pack.a.User user = new pack.a.User();
    }
}

 

  • PackageMain1과 Data는 pack이라는 패키지에 소속되어 있으므로, 같은 패키지에 있는 경우에는 패키지 경로를 생략해도 된다.
  • PackageMain1과 User는 서로 다른 패키지다. 패키지가 다르면 pack.a.User와 같이 패키지 전체 경로를 포함해서 클래스를 적어준다.

패키지 - import

import

패키지가 다르다고 pack.a.User와 같이 항상 전체 경로를 적기보단 import를 사용한다.

package pack;

import pack.a.User;

public class PackageMain2{
	public static void main(String[] args){
    	Data data = new Data();
        User user = new User(); // import 사용으로 패키지 명 생략 가능
    }
}

 

import를 사용하면 다른 패키지에 있는 클래스를 가져와서 사용할 수 있다.

import를 사용한 덕분에 패키지 명을 생략하고 클래스 이름만 적을 수 있다.

 

특정 패키지에 포함된 모든 클래스를 포함해서 사용하려면, import 시점에 *(별)을 사용한다.

import pack.a.*;

 

클래스 이름 중복

클래스 이름이 같아도 패키지 이름으로 구분해서 같은 이름의 클래스를 사용할 수 있다.

pack.a.User
pack.b.User

 

package pack;

import pack.a.User;

public class PackageMain3 {
	public static void main(String[] args){
    	User userA = new User();
        pack.b.User userB = new pack.b.User();
    }
}

 

클래스 이름이 둘 다 User이지만 패키지 이름으로 대상을 구분할 수 있다.

같은 이름의 클래스가 있다면 import는 둘중 하나만 선택할 수 있다. 자주 사용하는 클래스를 import하고 나머지를 패키지를 포함한

전체 경로로 적어준다, 둘 다 전체 경로를 적어주면 import를 사용하지 않아도 된다.

 

패키지 규칙

패키지 규칙

  • 패키지의 이름과 위치는 폴더(디렉토리) 위치와 같아야 한다. (필수적)
  • 패키지 이름은 모두 소문자를 사용해야 한다. (관례)
  • 패키지 이름의 앞 부분에는 일반적으로 회사의 도메인 이름을 거꾸로 사용한다.(관례)
    • 필수는 아니지만, 수 많은 라이브러리가 함께 사용되면 같은 패키지에 같은 클래스 이름이 존재할 수도 있다. 도메인 이름을 거꾸라 사용하면 이러한 문제를 방지할 수 있다.
    • 오픈소스나 라이브러리를 만들어서 외부에 제공하는 경우 꼭 지키는 것이 좋다.
    • 애플리케이션을 다른 곳에 공유하지 않고, 직접 배포하는 경우 보통 문제가 되지 않는다.

패키지와 계층 구조

패키지는 다음과 같은 계층 구조를 가진다.

  • a
    • b
    • c

총 3개의 패키지가 존재한다.

a, a.b, a.c

 

계층 구조상 a 패키지 하위에 a.b 패키지와 a.c 패키지가 있다.

눈에 보기에 계층 구조를 이룰 뿐이지, a 패키지와 a.b, a.c 패키지는 서로 완전히 다른 패키지이.

a 패키지의 클래스에서 a.b 패키지의 클래스가 필요하면 import 해서 사용해야 한다. 반대도 마찬가지이다.

 

패키지가 계층 구조를 이루더라도 모든 패키지는 서로 다른 패키지이다.

 

패키지 활용

큰 애플리케이션은 대략 다음과 같은 방식으로 패키지를 구성한다.

  • com.helloshop
    • user
      • User
      • UserService
    • product
      • Product
      • ProductService
    • order
      • Order
      • OrderService
      • OrderHistory

다른 패키지의 기능이 필요하면 import를 사용하면 된다.

public이 붙어있어야 다른 패키지에서 생성자를 호출할 수 있다.

 

패키지를 구성할 때 서로 관련된 클래스는 하나의 패키지에 모으고, 관련이 적은 클래스는 다른 패키지로 분리하는 것이 좋다.