라이브러리 vs 프레임워크의 차이

 

라이브러리

- 공통으로 사용될 수 있는 특정한 기능을 모듈화한 것

- 내가 직접 컨트롤할 수 있음.

- 프레임워크에 비해 자유로움.

 

프레임워크

- 공통으로 사용될 수 있는 특정한 기능을 모듈화한 것.

- 규칙이 엄격함.(폴더 구조, 파일 명 등)

- 제어권이 나한테 없음.(IOC)

 

디자인 패턴

- 프로그램을 설계할 때, 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 "규약" 형태로 만들어 놓은 것.

 

싱글톤 패턴

- 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴

- 데이터베이스 연결 모듈에 많이 쓰인다.

- 인스턴스를 생성할 때, 드는 비용이 줄어든다.

- 의존성이 높아진다.

 

 

중첩 클래스란?

- 클래스 내부에 클래스가 있는 형태

- 자바 기반의 UI 처리를 할 때, 사용자의 입력이나 외부의 이벤트에 대한 처리르 하는 곳에서 많이 사용했으나, 현재는 안드로이드 프로그래밍에서 위젯의 이벤트를 처리하는 핸들러를 구현할 때, 사용한다.

- 다른 클래스와 협력할 일이 적고, 외부 클래스와 밀접한 관련이 있다면 사용된다. -> 두 클래스를 한 번에 관리하기에 적합하고, 불필요한 관계를 감추고 높은 접근성을 얻을 수 있다.

- 외부 클래스와 내부 클래스가 서로의 멤버에 쉽게 접근할 수 있음.

- 소스의 가독성과 유지보수성을 높일 수 있다.

- 서로 관련 있는 클래스를 논리적으로 묶어서 표현함으로써, 코드의 캡슐화를 증가시킨다.

- 외부에서는 내부 클래스에 접근할 수 없으므로, 코드의 복잡성을 줄일 수 있다.

 

참고: https://velog.io/@blwasc/Java-%EC%A4%91%EC%B2%A9-%ED%81%B4%EB%9E%98%EC%8A%A4

 

[Java] 중첩 클래스

중첩 클래스(Nested class)란?, 중첩 클래스를 사용하는 이유, 중첩 클래스의 장점, 중첩 클래스의 종류, 내부 인터페이스(Nested Interface)란?

velog.io

 

 

* 중첩 클래스를 이용해서 활용한 예시

class Singleton {
	private static class singleInstanceHolder {
		private static final Singleton INSTANCE = new Singleton();
	}

	public static Singleton getInstance() {
		return singleInstanceHolder.INSTANCE;
	}
}

public class HelloWorld {
	public static void main(String[] args) {
		Singleton a = Singleton.getInstance();
		Singleton b = Singleton.getInstance();
		System.out.println(a.hashCode());
		System.out.println(b.hashCode());

		if (a == b) {
			System.out.println(true);
		}
	}
}

 

싱글톤 패턴의 단점

1. '독립적인' 인스턴스를 만들기가 어려움 -> 단위 테스트는 테스트가 서로 독립적이어야 하는데, 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로

 

단위테스트가 '독립적' -> 테스트를 어떤 순서로든 실행할 수 있어야 한다.

 

2. 모듈 간의 결합을 강하게 만들 수 있다. => 의존성 주입(DI)를 통해 결합도를 낮출 수 있음.

 

의존성

- 종속성이라고도 불림.

- A가 B에 의존성이 있다는 것은 B의 변경 사항에 대해 A 또한 변해야 한다는 것.

 

의존성 주입 장점

- 모듈들을 쉽게 교체할 수 있는 구조로 만들 수 있다. -> 메인 모듈이 '직접' 다른 하위 모듈에 대한 의존성을 주기보다는 중간에 의존성 주입자가 이 부분을 가로채 메인 모듈이 '간접적'으로 의존성 주입을 주는 것.

- 테스팅하기 쉽고, 마이그레이션하기도 수월함.

 

구현할 때, 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어 주기 때문에 애플리케이션 의존성 방향이 일관되고, 애플리케이션을 쉽게 추론할 수 있고, 모듈 간의 관계가 명확해짐.

 

의존성 주입 단점

- 모듈이 더 많이 분리되므로, 클래스 수가 많아지고 이로 인해, 약간의 런타임 패널티가 발생할 수 있음.

 

의존성 주입 원칙

"상위 모듈은 하위 모듈에서 어떠한 것도 가져와서는 안된다."

- 상위 모듈과 하위 모듈 모두 "추상화"에 의존해야 한다.

- 추상화는 "세부 사항"에 의존해서는 안된다.

 

팩토리 패턴

- 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴

- 상속관계가 있는 두 클래스에서 상위 클래스는 크게 뼈대를 결정하고, 하위 클래스는 객체 생성에 관한 구체적인 내용을 결정하는 패턴

- 상위 클래스는 객체 생성 방식에 대해 알 필요가 없고, 느슨한 결합이 가능하다.

- 객체 생성 로직이 따로 분리되어 있기 때문에 수정할 일이 있다면 그 부분만 고치면 되므로 유지보수성이 늘어난다.

- 전달받은 값에 따라 다른 객체를 생성하며 인스턴스의 타입을 정한다.

 

enum CoffeeType {
	LATTE,
	ESPRESSO
}

abstract class Coffee {
	protected String name;

	public String getName() {
		return name;
	}
}

class Latte extends Coffee {
	public Latte() {
		name = "Latte";
	}
}
class Espresso extends Coffee {
	public Espresso() {
		name = "Espresso";
	}
}

class CoffeeFactory {
	public static Coffee createCoffee(CoffeeType type) {
		switch (type) {
			case LATTE:
				return new Latte();
			case ESPRESSO:
				return new Espresso();
			default:
				throw new IllegalArgumentException("invalid type");
		}
	}
}

public class Main {
	public static void main(String[] args) {
		Coffee coffee = CoffeeFactory.createCoffee(CoffeeType.LATTE);
		System.out.println(coffee.getName());
	}
}

 

Enum

- 상수의 집합을 정의할 때, 사용되는 타입

- 상수뿐만 아니라 메서드를 집어 넣어 관리할 수도 있음.

- 본질적으로  thread safe 하기 때문에 싱글톤 패턴을 만들 때 도움이 된다.

 

전략 패턴

- 객체의 행위를 바꾸고 싶은 경우, "직접" 수정하지 않고 전략이라고 부르는 '캡슐화된 알고리즘'을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴

- 우리가 어떤 상품을 구매할 때, 네이버페이, 카카오페이 등 다양한 방법으로 결제하듯이 결제 방식의 '전략'만 바꿔서 두 가지 방식으로 결제하는 것

 

interface PaymentStrategy {
	public void pay(int amount);
}

class KAKAOCardStrategy implements PaymentStrategy {
	private String name;
	private String cardNumber;
	private String cvv;
	private String dateOfExpiry;

	public KAKAOCardStrategy(String name, String cardNumber, String cvv, String dateOfExpiry) {
		this.name = name;
		this.cardNumber = cardNumber;
		this.cvv = cvv;
		this.dateOfExpiry = dateOfExpiry;
	}

	@Override
	public void pay(int amount) {
		System.out.println(amount + " paid using KAKAOCard.");
	}
}

class LUNACardStrategy implements PaymentStrategy {
	private String emailId;
	private String password;

	public LUNACardStrategy(String emailId, String password) {
		this.emailId = emailId;
		this.password = password;
	}

	@Override
	public void pay(int amount) {
		System.out.println(amount + " paid using LUNACard.");
	}
}

class Item {
	private String name;
	private int price;

	public Item(String name, int price) {
		this.name = name;
		this.price = price;
	}

	public String getName() {
		return name;
	}

	public int getPrice() {
		return price;
	}
}

class ShoppingCart {
	List<Item> items;

	public ShoppingCart() {
		this.items = new ArrayList<>();
	}

	public void addItem(Item item) {
		this.items.add(item);
	}

	public void removeItem(Item item) {
		this.items.remove(item);
	}

	public int calculateTotal() {
		int sum = 0;
		for (Item item : items) {
			sum += item.getPrice();
		}

		return sum;
	}

	public void pay(PaymentStrategy paymentMethod) {
		int amount = calculateTotal();
		paymentMethod.pay(amount);
	}
}

public class HelloWorld {
	public static void main(String[] args) {
		ShoppingCart cart = new ShoppingCart();

		Item A = new Item("knudolA", 100);
		Item B = new Item("knudolB", 300);

		cart.addItem(A);
		cart.addItem(B);
		
		// pay by LUNACard
		cart.pay(new LUNACardStrategy("ex1@example.com", "pukubababo"));
		
		// pay by KAKAOCard
		cart.pay(new KAKAOCardStrategy("ex2", "123456", "123", "12/01"));

		/**
		 * 400 paid using LUNACard.
		 * 400 paid using KAKAOCard.
		 */
	}
}

 

컨텍스트

- 어떠한 작업을 완료하는데 필요한 모든 관련 정보를 말한다.

 

 

 

출처: 면접을 위한 전공 CS노트

https://www.skcareers.com/Recruit/Detail/R241397

 

SK Careers

SK그룹 채용 플랫폼

www.skcareers.com

 

 

 

'취준' 카테고리의 다른 글

SSAFY 11기 합격 후기(전공자)  (4) 2023.12.23
신한투자증권 프로 아카데미 3기 후기[합격]  (0) 2023.12.13

https://www.acmicpc.net/problem/2877

 

2025년 엠로 상반기 코테와 유사한 문제였다.
규칙을 잘보면, 이진수처럼 표현이 가능해진다. 0 : 4, 4 : 7

 

idx idx에 해당하는 입력되는 숫자 idx에 해당하는 이진수 이진수 + 1
1 4 1 1
2 7 10 11
3 44 11 100
4 47 100 101
5 74 101 110
6 77 110 111
7 444 111 1000
8 447 1000 1001
9 474 1001 1010

 

첫 번째 이진수 자리를 지워주면 각각 대응되서 숫자가 표현되는 것을 확인할 수 있다.

 

package _250320;

import java.util.*;
import java.io.*;

/**
 *packageName    : _250320
 * fileName       : BOJ_G5_2877_4와7
 * author         : moongi
 * date           : 3/21/25
 * description    :
 */
public class BOJ_G5_2877_4와7 {
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		String s = Integer.toBinaryString(Integer.parseInt(br.readLine()) + 1).replace('0', '4').replace('1', '7');

		StringBuilder sb = new StringBuilder();
		for (int i = 1; i < s.length(); i++) {
			sb.append(s.charAt(i));
		}
		System.out.println(sb);
	}
}

'알고리즘 > 기업별 유사 문제' 카테고리의 다른 글

백준 No.2169 로봇 조종하기  (0) 2025.03.21

 

https://www.acmicpc.net/problem/2169

 

 

해당 문제는 2025년 상반기 엠로 코딩테스트 문제와 유사하였다.

처음엔 별 생각 없이, bfs로 접근하였는데, 이후에 dp로 푸는 문제라는 것을 깨달았다. 그러나, 최댓값을 구하는 과정에서 풀이 방식이 생각나지 않았다.

 

package _250320;

import java.util.*;
import java.io.*;

/**
 *packageName    : _250320
 * fileName       : BOJ_G2_2169_로봇조종하기
 * author         : moongi
 * date           : 3/21/25
 * description    :
 */
public class BOJ_G2_2169_로봇조종하기 {
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());

		int N = Integer.parseInt(st.nextToken());
		int M = Integer.parseInt(st.nextToken());

		int[][] arr = new int[N][M];
		int[][] dp = new int[N][M];
		int[][] tmp = new int[2][M];

		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < M; j++) {
				arr[i][j] = Integer.parseInt(st.nextToken());
			}
		}

		dp[0][0] = arr[0][0];
		for (int i = 1; i < M; i++) {
			dp[0][i] = dp[0][i - 1] + arr[0][i];
		}

		for (int i = 1; i < N; i++) {

			// 왼쪽에서 오른쪽으로 오는 것
			tmp[0][0] = dp[i - 1][0] + arr[i][0];
			for (int j = 1; j < M; j++) {
				tmp[0][j] = Math.max(tmp[0][j - 1], dp[i - 1][j]) + arr[i][j];
			}

			// 오른쪽에서 왼쪽으로 오는 것
			tmp[1][M - 1] = dp[i - 1][M - 1] + arr[i][M - 1];
			for (int j = M - 2; j >= 0; j--) {
				tmp[1][j] = Math.max(dp[i - 1][j], tmp[1][j + 1]) + arr[i][j];
			}

			for (int j = 0; j < M; j++) {
				dp[i][j] = Math.max(tmp[0][j], tmp[1][j]);
			}

		}

		System.out.println(dp[N-1][M-1]);

	}
}

'알고리즘 > 기업별 유사 문제' 카테고리의 다른 글

[Java] 백준 2877번 : 4와 7  (0) 2025.03.21

0. 해당 글을 쓰게 된 배경

더보기

기존에는 c++을 통해서 코테를 준비하였다.

그러나, SSAFY를 시작하게 되면서 전공자의 경우는 Java로 모든 수업이 진행된다고 하였다.

어차피 Spring framework도 사용하고, 요즘 백엔드 직무 관련해서 많은 기업들에서 Java, node.js, python등으로 많이 보는 경향이 있기에 이참에 코테 언어를 변경해서 공부해야겠다고 마음먹었다.

따라서 코테용 주요 함수등을 정리해보면 나와 같은 상황에 있는 사람들에게 조금이나마 도움이 되지 않을까 싶어 글을 쓰게 되었다.

 

 

1. 필드의 구분

  1. 클래스 변수(static variable)
  2. 인스턴스 변수(instance variable)
  3. 지역 변수(local variable)
class Car {

    static int modelOutput; // 클래스 변수
    String modelName;       // 인스턴스 변수
    
    void method() {
        int something = 10; // 지역 변수
    }
}

 

 

class Field {
    static int classVar = 10; // 클래스 변수 선언
    int instanceVar = 20; // 인스턴스 변수 선언
}

public class FieldEx2 {
    public static void main(String[] args) {

        int var = 30; // 지역 변수 선언
        System.out.println("var = " + var); // 지역 변수 참조

        Field myField1 = new Field(); // 인스턴스 생성
        Field myField2 = new Field(); // 인스턴스 생성

        System.out.println("Field.classVar = " + Field.classVar); // 클래스 변수 참조
        System.out.println("myField1 = " + myField1.classVar);
        System.out.println("myField2.classVar = " + myField2.classVar);

        myField1.classVar = 100; // 클래스 변수의 값을 변경

        System.out.println("Field.classVar = " + Field.classVar); // 클래스 변수 참조
        System.out.println("myField1 = " + myField1.classVar);
        System.out.println("myField2 = " + myField2.classVar);

        myField1.instanceVar = 200;

        System.out.println("myField1 = " + myField1.instanceVar); // 인스턴스 변수 참조
        System.out.println("myField2 = " + myField2.instanceVar);

    }
}

 

2. 메소드의 구분

  1. 클래스 메소드(static method)
  2. 인스턴스 메소드(instance method)
class Method {
    int a = 10, b = 20;
//    static int add() {return a + b;} // 다음과 같이 static 메소드는 메소드 내부에서 인스턴스 변수를 사용할 수 없다.
    int add() {return a + b;}
    static int add(int x, int y) {return x + y;}
}

public class TcpMethod2 {
    public static void main(String[] args) {
        System.out.println("Method.add(20, 30) = " + Method.add(20, 30));
        Method myMethod = new Method();
        System.out.println("myMethod.add() = " + myMethod.add());

    }
}

 

3. 초기화 블록

  1. 명시적 초기화
  2. 생성자를 이용한 초기화
  3. 초기화 블록을 이용한 초기화
    1. 인스턴스 초기화 블록
      1. 인스턴스 초기화 블록은 단순히 중괄호({})만을 사용하여 정의
      2. 인스턴스 초기화 블록은 생성자와 마찬가지로 인스턴스가 생성될 때마다 실행
      3. 인스턴스 초기화 블록이 생성자보다 먼저 실행
      4. 여러 개의 생성자가 있으면 모든 생성자에서 공통으로 수행되어야 할 코드를 인스턴스 초기화 블록에 포함하여 코드의 중복을 막을 수 있다. 
class Car {
    private String modelName;
    private int modelYear;
    private String color;
    private int maxSpeed;
    private int currentSpeed;

    { // 인스턴스 초기화 블록 : 단순히 중괄호({})만을 사용, 인스턴스가 생성될 때마다 실행, 인스턴스 초기화 블록이 생성자보다 먼저 실행
        this.currentSpeed = 0;
    }

    Car() {}

    public Car(String modelName, int modelYear, String color, int maxSpeed) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }

    public int getSpeed() {
        return currentSpeed;
    }
}
public class TcpMethod3 {
    public static void main(String[] args) {
        Car myCar = new Car();
        System.out.println("myCar.getSpeed() = " + myCar.getSpeed());
    }
}

 

 

2. 클래스 초기화 블록:

  1. 인스턴스 초기화 블록에 static 키워드를 추가하여 정의할 수 있다.
  2. 클래스가 처음으로 메모리에 로딩될 때 단 한 번만 실행됩니다.
class InitBlock {
    static int classVar; // 클래스 변수
    int instanceVar; // 인스턴스 변수

    static { // 클래스 초기화 블록을 이용한 초기화
        classVar = 10;
    }
}
public class Member04 {
    public static void main(String[] args) {
        System.out.println("InitBlock.classVar = " + InitBlock.classVar); // 클래스 변수에 접근
    }
}

 

4. 필드의 초기화 순서

  1. 클래스 변수: 기본값 -> 명시적 초기화 -> 클래스 초기화 블록
  2. 인스턴스 변수: 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블록 -> 생성자
class InitBlock {
    static int classVar = 10; // 클래스 변수의 명시적 초기화
    int instanceVar = 10; // 인스턴스 변수의 명시적 초기화

    static { // 클래스 초기화 블록을 이용한 초기화
        classVar = 20;
    }
    { // 인스턴스 초기화 블록을 이용한 초기화
        instanceVar = 20;
    }

    public InitBlock() {
        this.instanceVar = 30; // 생성자를 이용한 초기화
    }
}
public class Member04 {
    public static void main(String[] args) {
        System.out.println("InitBlock.classVar = " + InitBlock.classVar); // 클래스 변수에 접근
        InitBlock myInit = new InitBlock();
        System.out.println("myInit.instanceVar = " + myInit.instanceVar);
    }
}

 

+ Recent posts