JAVA 책으로 공부중인데 앞 쪽에 JAVA의 특징으로 멀티스레드가 언급되어 있었습니다

동시성과 병렬성에 대해서도 잠깐 언급되어 있는데

이 두 개념은 봐도봐도 헷갈립니다

 

그래서 이를 정리해봤습니다

 

동시성

동시성은 여러 작업이 동시에 진행되는 것처럼 보이게 하는 개념입니다

이는 시간상으로 겹치는 것처럼 보이지만, 실제로는 동시에 실행되지 않을 수 있습니다

프로그램이 여러 작업을 동시에 다루는 것을 통해, 시스템의 응답성을 향상시키고 작업을 더 효율적으로 다룰 수 있습니다

 

병렬성

병렬성은 여러 작업이 동시에 실행되는 개념으로, 실제로 동시에 여러 작업이 처리됩니다

주로 다중 코어 또는 다중 프로세서 시스템에서 성능을 극대화하기 위해 사용됩니다

 

차이점

- 실행 방식: 동시성은 하나의 프로세스 내에서 여러 스레드가 번갈아가면 실행되지만 병렬성은 여러 프로세스나 스레드가 동시에 실행됩니다

- 목적: 동시성은 주로 입출력 바운드 작업에 유용하며, 병렬성은 CPU 바운드 작업에 유용합니다

 

소프트웨어 개발에서 MVC (Model - View - Controller) 패턴은 코드의 구조화와 유지보수성을 향상시키는 데 도움을 주는 중요한 디자인 패턴 중 하나입니다

이 글에서는 MVC 패턴의 개념, 장점, 그리고 사용 사례에 대해 살펴보겠습니다

 

1. MVC 패턴 소개

MVC 패턴은 소프트웨어를 세 가지 구성 요소로 분리합니다

 

  • Model(모델): 데이터와 비즈니스 로직을 관리합니다. 데이터의 상태 변경을 감지하고, 변경 사항을 View에 통지합니다
  • View(뷰): 사용자 인터페이스를 담당합니다. 모델의 데이터를 시작적으로 표현하고, 사용자의 입력을 Controller에 전달합니다
  • Controller(컨트롤러): 사용자의 입력을 받아 모델을 업데이트하거나, 모델의 상태에 따라 적절한 뷰를 갱신합니다

2. MVC의 장점

코드 재사용성

MVC 패턴은 각각의 역할이 명확하게 나뉘어져 있기 때문에, 각 구성 요소를 독립적으로 개발하고 테스트할 수 있습니다

이는 코드의 재사용성을 높이고 개발 생산성을 향상시킵니다

 

유지보수성 향상

각각의 구성 요소가 분리되어 있어 변경이 필요할 때 해당 부분만 수정할 수 있습니다

이는 유지보수성을 향상시키고 전체 소프트웨어 시스템의 안정성을 높입니다

 

확장 용이성

새로운 기능이나 요구 사항이 추가될 때, 해당 기능과 관련된 부분만을 수정하면 되기 때문에 시스템을 확장하기가 용이합니다

 

3. MVC 패턴의 사용 사례

웹 개발

MVC 패턴은 웹 개발에서 주로 사용됩니다

프론트엔드에서는 뷰가 사용자 인터페이스를 담당하고, 백엔드에서는 모델과 컨트롤러가 데이터와 비즈니스 로직을 처리합니다

 

데스크톱 응용 프로그램

MVC 패턴은 데스크톱 응용 프로그램에서도 효과적으로 사용됩니다

GUI 프렘임워트에서는 사용자 인터페이스 구성 요소를 뷰로 처리하고, 애플리케이션 로직을 컨트롤러가 담당합니다

 

 

엊그제 친구에게 레전드 썰을 들었습니다

친구의 직장 후배인데, 코딩 스타일이 개떡 같더군요

 

check 함수 안에서 DB작업을 하고, 함수 이름을 func2(), func3() 이런 식으로 짓는다더라고요

이야기를 듣는데 숨이 막혔습니다

 

그래서 오늘 주제는 클린 코드입니다

 

클린 코드의 중요성

1. 가독성 확보

코드는 개발자가 읽기 쉽고 이해하기 쉬워야 합니다

함수와 변수의 이름은 명확하고 간결하게 작성되어야 하며, 주석은 필요한 경우에만 사용되어야 합니다

(참고로 42서울에서의 코딩 컨벤션은 함수당 25줄 제한, 한 줄에 80글자 제한 등이 있었습니다)

 

2. 유지보수성 향상

클린 코드는 변경이 쉽고 유지보수가 간편합니다

새로운 기능 추가나 버그 수정이 빠르게 이루어질 수 있도록 코드는 작성하는 것이 중요합니다

 

3. 버그 감소

클린 코드는 버그 발생 가능성을 줄입니다

명확한 로직과 간결한 코드는 개발자가 실수를 줄일 수 있도록 도와줍니다

 

클린 코드의 원칙

1. 의미 있는 이름 사용

변수, 함수, 클래스 등의 이름은 해당 역할을 명확히 나타내야 합니다

일반적인 약어는 피하고, 이름의 길이보다는 의미를 중시해야 합니다

보통은 변수는 명사, 함수는 동사를 사용합니다

 

2. 작은 함수 사용

함수는 작고 명확해야 합니다

한 함수는 한 가지 일만 담당하도록 작성하여 코드의 가독성을 높입니다

 

3. 주석은 필요한 곳에만 사용

코드 자체가 자명하게 설명되지 않는 부분에 주석을 추가합니다

주석은 최소화 하고 코드 자체가 설명할 수 있도록 노력해야 합니다

(코드 자체가 자명하냐? 는 판단은 개발자 실력에 따라 다를 것 같습니다. 적절한 상황에 좋은 주석을 다는 고민이 필요합니다)

 

4. 불필요한 코드 제거

사용되지 않는 코드는 제거되어야 합니다

불필요한 코드는 혼란을 야기하고 유지보수를 어렵게 만듭니다

(제 친구의 직장 후배가 안 쓰는 함수를 삭제를 안 하고 남겨두었다고 합니다..ㅎ)

 

결론

클린 코드는 단순히 코딩 스타일이나 규약을 따르는 것 이상의 의미를 가지고 있습니다

클린 코드를 통해 개발자 간의 협업이 원활하게 이루어지며, 지속적인 품질 향상이 가능해집니다

어제 추상 클래스와 추상 메서드를 정리하면서 인터페이스와 추상 클래스의 차이점이 궁금해졌습니다

Java에서 인터페이스와 추상 클래스는 둘 다 추상화를 통한 객체 지향 프로그래밍의 핵심 개념입니다

그러나 이 둘은 목적과 특징에서 차이가 있습니다

이 글에서는 Java에서 인터페이스와 추상 클래스의 주요 차이점에 대해 알아보겠습니다

 

1. 인터페이스 (Interface)

인터페이스는 Java에서 다중 상속을 지원하고, 클래스 간의 계약(Contract)을 정의하는데 주로 사용됩니다

다음은 인터페이스의 주요 특징입니다

 

  • 추상 메서드(Abstract Method): 모든 메서드가 추상 메서드로 선언되어 있습니다. 구현은 하위 클래스에서 이루어집니다
  • 다중 상속: 여러 인터페이스를 구현할 수 있습니다
  • 상수(Constant): 인터페이스에서는 상수를 정의할 수 있습니다. 이는 자동으로 `public static final`로 설정됩니다.
  • 인터페이스 간 상속: 인터페이스는 다른 인터페이스를 확장할 수 있습니다

 

2. 추상 클래스 (Abstrct Class)

추상 클래스는 클래스이면서 일부 메서드가 구현되지 않고 추상 메서드로 남겨진 클래스입니다

다음은 추상 클래스의 주요 특징입니다

 

  • 일반 메서드와 추상 메서드 혼합: 추상 클래스는 일반 메서드와 추상 메서드를 함께 포함할 수 있습니다
  • 단일 상속: Java에서는 단일 상속만을 지원하므로, 추상 클래스도 이 조건을 따릅니다
  • 인터페이스 구현 가능: 추상 클래스는 인터페이스를 구현할 수 있습니다

 

3. 사용 상황

인터페이스

다중 상속이 필요하건, 계약을 명확하게 정의해야 할 때 사용합니다

예를 들어 여러 클래스에서 공통적으로 구현해야 하는 메서드가 있을 때 유용합니다

 

추상 클래스

공통된 메서드 구현이 필요하며, 또한 상속을 통해 확장하고자 할 때 사용합니다

추상 클래스는 하위 클래스에게 일부 구현을 강제하고 나머지는 선택적으로 제공할 수 있습니다

 

 

안녕하세요!

이번 글에서는 Java의 추상 메서드에 대해 알아보겠습니다

추상 메서드는 객체지향 프로그래밍의 중요한 개념 중 하나로, 클래스를 설계하고 확장하는 데에 있어서 유용하게 활용됩니다

그럼 알아보도록 하겠습니다

 

추상 메서드란?

추상 메서드는 선언만 있고 본문이 없는 메서드입니다

이 메서드를 가진 클래스를 추상 클래스라고 부르며, 추상 클래스는 직접 객체를 생성할 수 없습니다

대신, 이 추상 클래스를 상속받은 하위 클래스에서 추상 메서드를 반드시 구현해야 객체를 생성할 수 있습니다

이를 통해 메서드의 일관성을 유지하고, 다형성을 구현할 수 있습니다

 

abstract class Shape {
    abstract void draw();
}

class Circle extends Shape {
    void draw() {
        System.out.println("원을 그립니다.");
    }
}

class Square extends Shape {
    void draw() {
        System.out.println("사각형을 그립니다.");
    }
}

 

위의 예제에서 Shape 클래스는 추상 메서드 draw를 가지고 있습니다

이 클래스를 상속받은 Circle과 Square 클래스에서는 반드시 draw 메서드를 구현해야 합니다

 

추상 클래스의 활용

  1. 일관성 있는 디자인 구현: 여러 하위 클래스에서 동일한 메서드 시그니처를 유지하면서 각 클래스마다 다르게 구현할 수 있습니다
  2. 다형성 구현: 추상 클래스를 상속받아 각자 다르게 구현된 메서드를 통해 다형성을 구현할 수 있습니다
  3. 강제성 부여: 하위 클래스에서 반드시 구현해야 하는 메서드를 정의함으로써, 해당 메서드의 누락을 방지하고 안정성을 확보할 수 있습니다

 

추상 클래스와 인터페이스의 차이

Java에서는 인터페이스 역시 추상 메서드를 가질 수 있습니다

그러나 추상 클래스와 인터페이스의 큰 차이점 중 하나는 다중 상속을 지원하는지 여부입니다

추상 클래스는 단일 상속만을 허용하지만, 인터페이스는 다중 상속을 허용합니다

다중 상속이란, 자식 클래스가 둘 이상의 부모를 가지는 것을 의미합니다

 

interface Drawable {
    void draw();
}

class Circle implements Drawable {
    void draw() {
        System.out.println("원을 그립니다.");
    }
}

class Square implements Drawable {
    void draw() {
        System.out.println("사각형을 그립니다.");
    }
}

 

마무리

추상 메서드는 객체 지향 프로그래밍에서 클래스의 일관성을 유지하고, 다형성을 활용하기 위한 강력한 도구입니다

추상 클래스와 인터페이스를 통해 프로그램의 설계를 유연하게 할 수 있으며, 코드의 채사용성과 유지보수성을 향상시킬 수 있습니다

Java에서는 이러한 추상 메서드를 통해 높은 수준의 객체 지향 프로그래밍을 구현할 수 있습니다

'-- Language -- > Java' 카테고리의 다른 글

[JAVA] 접근제어자 이해하기  (0) 2023.12.18
[JAVA] Java Doc 주석  (0) 2023.12.15
[JAVA] 인터페이스와 추상 클래스의 차이  (0) 2023.12.09
[JAVA] for each 문  (0) 2023.11.24
[JAVA] new 키워드 및 메모리 동작  (0) 2023.11.23

- 코드 작성 순서

1. 설계: CRUD, 어떤 기능이 있는 프로그램을 만들지에 대한 설명

2. 데이터 명세: ERD, 속성(멤버변수) 정의

3. 한글 코딩

4. 코딩

5. 유효성 검사 (코딩 단계에서 하지 말 것!)

6. 모듈화

 

- 시험 준비

1. 연산자 우선순위 복습하기

2. 배열의 사용 조건

    1. 서로 관련된  데이터

    2. 자료형이 같은 데이터

    3. 저장할 데이터 개수를 정확히 알고 있어야 함

 

- JAVA OOP

1. 클래스 객체 = new 생성자(); // 객체화, 인스턴스화

2. 오버로딩: 함수명 중복정의 허용

3. 오버라이딩: 메서드 재정의

 

- 추상클래스 & 추상메서드

abstract class Shape {	// 추상 클래스
	String name;
	double area;
	
	Shape(String name) {
		this.name = name;
		this.area = 0.0;
	}
	
	abstract void printInfo();	// 추상 메서드: 하위 클래스에 오버라이딩 강제
}

1. 부모클래스를 정의하기 위해 생김

2. 객체를 정의하는데 관심이 없다 -> 객체 생성이 불가능

3. 클래스를 정의하는데 관심이 있다

4. 추상클래스 사용 이유

    - 객체화를 막으려고

    - 추상메서드를 사용하기 위함 -> 메서드 오버라이딩 강제

 

- 동적 바인딩: 가장 마지막에 재정의한 메서드가 자동으로 호출되는 현상 (다형성)

 

- 인터페이스

1. 클래스가 아님

2. 갖고 있는 모든 메서드가 public abstract 추상 메서드 -> 오버라이딩 강제

3. implements 키워드 사용

클래스 다이어그램
플로우 차트

- 아이템 슬롯은 최대 5개

- 골드 시스템

- 강화 확률은 시도 횟수와 몇 강인지에 영향을 받음

오버라이딩                   vs        오버로딩

==================================

함수명이 동일                          함수명이 동일

메서드 시그니쳐 같음               메서드 시그니쳐 다름

상속 관계에서 발생                  상속이랑 무관

메서드 재정의                          함수명 중복정의 허용

메서드가 1개                            함수가 N개

 

@어노테이션

- 코드 가독성 향상

- 메모리 성능 향상

- 설정 사항에 대한 설명

 

모든 자식 클래스의 생성자 가장 첫 줄에는 부모 클래스의 기본 생성자가 자동 호출된다

부모 클래스에 기본 생성자가 없는 경우는 super 키워드를 사용해서 부모 클래스의 다른 생성자를 호출할 수 있다

 

개발자가 만든 변수 == 객체 ~= 인스턴스 instance

멤버 변수 == 필드 == 속성 == attribute == property

함수 != 메서드 (구분해서 사용하자!!)

 

원시타입은 초기화를 안 하면 -> err

heap 메모리 영역은 자동 초기화 해준다

 

생성자 함수는 메모리 주소를 반환하기 때문에 반환값이 없다

 

this를 사용해서 멤버 변수를 불러와야 더 빠르다

this를 사용하지 않으면 범위를 기준으로 찾아가기 때문!

 

생성자보다 먼저 수행되는 코드는 존재할 수 없다!

 

static 키워드: 멤버 변수가 아니다, 공유 자원이다, 클래쓰 소속이다

final 키워드: 상수, 값이 안 바뀐다

PI는 static 키워드이기 때문에 c1.PI을 수정하면 c2.PI 값도 바뀐다

 

package class02;

public class Test01 {

	public static void main(String[] args) {

		/*
		 * 선택정렬 코드 작성
		 * */

		int[] datas = {1, 50, 34, 7};
		int tmp, minIdx;
		
		for (int a = 0; a < datas.length - 1; a++) {
			minIdx = a;
			for (int i = a + 1; i < datas.length; i++) {
				if (datas[i] < datas[minIdx]) {
					minIdx = i;
				}
			}
			tmp = datas[a];
			datas[a] = datas[minIdx];
			datas[minIdx] = tmp;
		}
		
		System.out.print("[ ");
		for (int data: datas) {
			System.out.print(data + " ");
		}
		System.out.println("]");
	}
	
	/*
	 * 디버깅표
	 * 
	 * datas               minIdx    a    a < 3    i    i < 4    datas[i] < datas[minIdx]
	 * ==================================================================================
	 * [ 1, 50, 34, 7 ]              0    T
	 *                     0                       1    T        F
	 *                                             2    T        F
	 *                                             3    T        F
	 *                                             4    F
	 * [ 1, 50, 34, 7 ]              1    T
	 *                     1                       2    T        T
	 *                     2                       3    T        T
	 *                     3                       4    F
	 * [ 1, 7, 34, 50 ]              2    T
	 *                     2                       3    T        F
	 *                                             4    F
	 * [ 1, 7, 34, 50 ]              3    F       
	 * 
	 * */

}

 

선택 정렬을 공부하다가 추가 의문 사항이 생겼다

선택 정렬은 불안정 정렬이다..왠지 안정일 거 같은 느낌이 들어서 확인해보자

 

 

package class02;

import java.util.Scanner;

class Pair {
    private int n;
    private char c;

    Pair(int n, char c) {
        this.n = n;
        this.c = c;
    }
//    Pair() {
//    }

    public int getN(){
        return n;
    }

    public char getC(){
        return c;
    }
}


public class Test02 {

	public static void main(String[] args) {

		/*
		 * 선택정렬 코드 작성
		 */

		/*
		 * 
		 * 여러 테스트 케이스를 넣기 위한 콘솔 입력 받기 입력 예시는 아래와 같다 3 5 --> 테스트 케이스의 수, 각 케이스의 길이 0 1 5
		 * 2 6 --> 각 테스트 케이스 2 2 3 4 5 4 2 12 9 0
		 * 
		 */

		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int len = sc.nextInt();

		for (int i = 0; i < n; i++) {
			
			/*
			 * 동일 값을 구분하기 위해 pair의 배열로 저장하자
			 * pair의 규칙은 다음과 같다
			 * <값, 구분자>
			 * <1, a>, <1, b> --> 같은 1의 값이지만 a와 b로 구분할 수 있다
			 * */
//			Pair p = new Pair(1, 'c');
			Pair[] datas = new Pair[len];
			char c = 'a';
			for (int j = 0; j < len; j++) {
				datas[j] = new Pair(sc.nextInt(), c++);
			}

			// 정렬 전 확인
			System.out.print("[ ");
			for (Pair data : datas) {
				System.out.print("<" + data.getN() + "," + data.getC() + "> ");
			}
			System.out.println("]");

			// 정렬
			int minIdx;
			Pair tmp;
			
			for (int a = 0; a < datas.length - 1; a++) {
				minIdx = a;
				for (int k = a + 1; k < datas.length; k++) {
					if (datas[k].getN() < datas[minIdx].getN()) {
						minIdx = k;
					}
				}
				tmp = datas[a];
				datas[a] = datas[minIdx];
				datas[minIdx] = tmp;
			}

			// 결과 확인 
			System.out.print("[ ");
			for (Pair data : datas) {
				System.out.print("<" + data.getN() + "," + data.getC() + "> ");
			}
			System.out.println("]");
		}
	}
}

 

코드는 위와 같이 작성했다

Pair를 이용해서 같은 값을 구분했다

불안정되는 케이스는 바로 찾았다

중복되는 3의 값이 0, 1이 정렬되는 과정에서 뒤섞이게 된다

 

궁금증 해결!

package class01;

public class Test01 {

	public static void main(String[] args) {
		// 삽입 정렬
		
		int[] datas = {100, 5, 60, 1000, 30};
		
		int pivot;
		for (int a = 1; a < datas.length; a++) {
			pivot = datas[a];
			for (int i = a; i > -1; i--) {
				if (pivot < datas[i]) {
					datas[i+1] = datas[i];
					datas[i] = pivot;
				}
			}
		}
		
		System.out.print("[ ");
		for (int data: datas) {
			System.out.print(data + " ");
		}
		System.out.println("]");
	}

}

 

디버깅표는 아래와 같이 나왔다

수업 중 다른 팀의 발표 주제가 버블 정렬이었다

발표용으로 제출된 코드를 내 기준에 맞게 리팩토링 해보자

 

발표용 코드

package class01;

public class Test01 {

   
   public static void main(String[] args) {
      
      
      
      int[] ar = {3,2,5,1,4};
      
      int[] arr= new int[5];
      arr[0]=3;
      arr[1]=2;
      arr[2]=5;
      arr[3]=1;
      arr[4]=4;
      
      
      // 정렬을 몇번할지 결정하는 반복문
      // 배열의 요소개수만큼 수행하겠다! == 5번 정렬하겠다!
      for (int j = 0; j < ar.length; j++) {
         boolean flag = true;
         
         
         // 배열을 1회 정렬할때 사용되는 반복문
         for (int i = 0; i < ar.length-1-j; i++) {
            // 임시 저장변수, 임시 변수
            // 변수값들을 서로 교환하려면 반드시 tmp가 필요함!
            // tmp,temp 변수명이 발견된다면?
            // 아~ 교환하려나보다~~ 예상가능함
            
            if(ar[i]>ar[i+1]) {
               int temp = ar[i];
               ar[i] = ar[i+1];
               ar[i+1]=temp;
               flag = false;
            }
         }
         // 1번 정렬을 마친상태 == 1회전 정렬이 끝났다.
         
         
         
         
         if(flag) {
            break;
         }
         
         
         for (int p = 0; p < ar.length; p++) {
            System.out.print(ar[p]+" ");
         }

         System.out.println();
      }
      
      
            
            
   }

}

 

수정한 코드

수정 이유는 주석으로 작성

package class01;

public class Test01 {
   public static void main(String[] args) {
      
      int[] ar = {3,2,5,1,4};
      
      int tmp; // for문 밖에 선언해서 한 번만 선언하기
      boolean flag;
      for (int j = 0; j < ar.length - 1; j++) { // 효율을 위해 범위를 하나 줄이자
    	 flag = true;
    	 
         for (int i = 0; i < ar.length - 1 - j; i++) {
            if (ar[i] > ar[i+1]) {
               tmp = ar[i];
               ar[i] = ar[i+1];
               ar[i+1] = tmp;
               flag = false;
            }
         }
         if (flag) {
            break;
         }
         
         for (int p = 0; p < ar.length; p++) {
            System.out.print(ar[p] + " ");
         }
         System.out.println();
      }
   }
}

+ Recent posts