라이브러리 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노트

+ Recent posts