개발자상식 <백엔드 개발자> (6)[책리뷰 & Book review]
본문 바로가기

컴퓨터공부/책리뷰 & book review

개발자상식 <백엔드 개발자> (6)[책리뷰 & Book review]

by Life & study 2024. 1. 15.
반응형

개발자상식 <백엔드 개발자> (6)

[책리뷰 & Book review]

 

 

자바와 파이썬에서 주로 사용되는 디자인 패턴에 대해 


자바에서는 주로 객체 지향 디자인 패턴이 사용되며, 

그중에서도 스프링 프레임워크와 같은 웹 개발에서는 MVC(Model-View-Controller) 패턴이 널리 쓰입니다.

MVC 패턴: 이 패턴은 애플리케이션을 Model, View, Controller 세 부분으로 나눕니다.
Model: 데이터와 비즈니스 로직을 처리합니다.
View: 사용자 인터페이스와 데이터의 시각적 표현을 담당합니다.
Controller: Model과 View 사이의 인터페이스 역할을 합니다.
스프링 MVC 코드 예제:

java

@Controller
public class MyController {
    @Autowired
    private MyService myService;

    @RequestMapping("/")
    public String home(Model model) {
        model.addAttribute("message", myService.getMessage());
        return "home";
    }
}


위 코드에서 MyController는 컨트롤러, MyService는 모델, "home"은 뷰에 해당합니다.

파이썬에서도 다양한 디자인 패턴이 사용됩니다. 

그중에서도 웹 개발에서는 Flask, Django 등의 프레임워크에서 MVC 패턴과 유사한 MVT(Model-View-Template) 패턴이 널리 쓰입니다.

MVT 패턴: 이 패턴도 MVC 패턴과 유사하게 애플리케이션을 Model, View, Template 세 부분으로 나눕니다.
Model: 데이터와 비즈니스 로직을 처리합니다.
View: Model로부터의 데이터를 적절한 Template에 전달하는 역할을 합니다.
Template: 사용자 인터페이스와 데이터의 시각적 표현을 담당합니다.
Django MVT 코드 예제:

python

# models.py
from django.db import models

class MyModel(models.Model):
    message = models.CharField(max_length=200)

# views.py
from django.shortcuts import render
from .models import MyModel

def home(request):
    message = MyModel.objects.get(id=1).message
    return render(request, 'home.html', {'message': message})

# home.html
<!DOCTYPE html>
<html>
<body>
    <h1>{{ message }}</h1>
</body>
</html>


위 코드에서 MyModel은 모델, home 함수는 뷰, 'home.html'은 템플릿에 해당합니다.

 

 

 

DFS(깊이 우선 탐색, Depth-First Search)와 BFS(너비 우선 탐색, Breadth-First Search) 알고리즘

 

깊이 우선 탐색(DFS)과 너비 우선 탐색(BFS)에 대해 각각 자바와 파이썬에서 어떻게 쓰이는지 설명드리겠습니다.

먼저 DFS(깊이 우선 탐색)와 BFS(너비 우선 탐색)에 대해 간략하게 설명하겠습니다.

DFS(깊이 우선 탐색): 시작 정점에서 시작해서 다음 분기(branch)로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방법입니다.
BFS(너비 우선 탐색): 시작 정점에서 가까운 정점부터 탐색하는 방법입니다.
아래는 간단한 트리 그림입니다.

 

    1
   / \
  2   3
 / \   \
4   5   6


DFS와 BFS를 이 트리에서 구현한 결과는 다음과 같습니다.

DFS: 1 - 2 - 4 - 5 - 3 - 6
BFS: 1 - 2 - 3 - 4 - 5 - 6


DFS(깊이 우선 탐색)
DFS는 루트 노드(혹은 다른 임의의 노드)에서 시작해서 다음 분기(branch)로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방법입니다.


자바 코드 예시:


DFS (Java)

java
import java.util.*;

class Node {
    int data;
    ArrayList<Node> children = new ArrayList<>();
    
    Node(int data) {
        this.data = data;
    }
}

public class Main {
    static void dfs(Node node) {
        Systehttp://m.out.print(node.data + " ");
        for (Node child : node.children) {
            dfs(child);
        }
    }

    public static void main(String[] args) {
        Node root = new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        Node node4 = new Node(4);
        Node node5 = new Node(5);
        Node node6 = new Node(6);

        root.children.add(node2);
        root.children.add(node3);
        node2.children.add(node4);
        node2.children.add(node5);
        node3.children.add(node6);

        dfs(root);  // 출력: 1 2 4 5 3 6
    }
}


BFS (Java)
java

import java.util.*;

class Node {
    int data;
    ArrayList<Node> children = new ArrayList<>();
    
    Node(int data) {
        this.data = data;
    }
}

public class Main {
    static void bfs(Node root) {
        Queue<Node> queue = new LinkedList<>();
        queue.offer(root);
        
        while (!queue.isEmpty()) {
            Node node = queue.poll();
            Systehttp://m.out.print(node.data + " ");
            for (Node child : node.children) {
                queue.offer(child);
            }
        }
    }

    public static void main(String[] args) {
        Node root = new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        Node node4 = new Node(4);
        Node node5 = new Node(5);
        Node node6 = new Node(6);

        root.children.add(node2);
        root.children.add(node3);
        node2.children.add(node4);
        node2.children.add(node5);
        node3.children.add(node6);

        bfs(root);  // 출력: 1 2 3 4 5 6
    }
}


다음은 파이썬 코드입니다.

DFS (Python)

python
class Node:
    def __init__(self, data):
        self.data = data
        self.children = []

def dfs(node):
    print(node.data, end=' ')
    for child in node.children:
        dfs(child)

root = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node6 = Node(6)

root.children.append(node2)
root.children.append(node3)
node2.children.append(node4)
node2.children.append(node5)
node3.children.append(node6)

dfs(root)  # 출력: 1 2 4 5 3 6
BFS (Python)
python
from collections import deque

class Node:
    def __init__(self, data):
        self.data = data
        self.children = []

def bfs(root):
    queue = deque([root])
    while queue:
        node = queue.popleft()
        print(node.data, end=' ')
        for child in node.children:
            queue.append(child)

root = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node6 = Node(6)

root.children.append(node2)
root.children.append(node3)
node2.children.append(node4)
node2.children.append(node5)
node3.children.append(node6)

 

bfs(root)  # 출력: 1 2 3 4 5 6


위 코드들에서 Node 클래스를 생성하여 트리를 구현하였습니다. DFS는 재귀를 통해 깊이를 우선적으로 탐색하고, BFS는 큐를 사용하여 너비를 우선적으로 탐색합니다. 이렇게 두 방식은 각각의 특성에 따라 적절하게 사용됩니다.

 

 

 

 

 

계층화란?



계층화 시스템(Layered System)
클라이언트는 직접 연결된 서버에만 요청을 보내고, 네트워크 아키텍처의 세부 사항을 알지 못합니다.
예를 들어, 클라이언트는 웹 서버에 요청을 보내고 웹 서버는 데이터베이스 서버에 요청을 보낼 수 있습니다. 이 경우 클라이언트는 데이터베이스 서버의 존재를 알지 못합니다.

 

유니폼 인터페이스(Uniform Interface)
REST는 HTTP 표준 메서드(GET, POST, PUT, DELETE 등)를 사용하여 자원을 조작합니다.
예를 들어, 클라이언트는 HTTP GET 요청을 사용하여 서버의 특정 자원을 요청하고, 서버는 해당 자원의 표현을 클라이언트에게 반환합니다.


자원의 식별
REST는 URI(Uniform Resource Identifier)를 사용하여 자원을 식별합니다.
예를 들어, http://example.com/users/1 는 ID가 1인 사용자를 식별하는 URI입니다.


자원의 표현
서버는 클라이언트에게 자원의 표현(예: JSON, XML)을 전송하고, 클라이언트는 이를 이해하고 처리합니다.
예를 들어, 서버는 사용자 정보를 JSON 형태로 클라이언트에게 전송할 수 있습니다.


메시지의 자기 설명성(Self-descriptiveness)
메시지는 자신을 어떻게 처리해야 하는지 충분한 정보를 포함해야 합니다.
예를 들어, HTTP 메서드(GET, POST, PUT, DELETE 등)는 요청이 어떤 목적으로 수행되는지를 나타냅니다.
하이퍼미디어를 통한 애플리케이션 상태 전이(HATEOAS: Hypermedia As The Engine Of Application State)
클라이언트는 서버로부터 얻은 하이퍼미디어 링크를 통해 애플리케이션 상태를 전이시킵니다.


예를 들어, 서버로부터 반환된 사용자 정보에는 사용자의 상세 정보, 수정, 삭제 등을 위한 링크가 포함될 수 있습니다. 클라이언트는 이 링크를 통해 해당 액션을 수행합니다.
이처럼, REST 아키텍처와 계층화 시스템은 특정 코드를 작성하는 것이 아니라 시스템을 설계하고 구현하는 방법론에 가까운 개념입니다. 따라서 이러한 원칙에 따라 시스템을 설계하고 구현하는 것이 중요합니다.

 

 

 

 

 

 

자바 오버라이딩과 오버로드

 

자바에서 오버로딩(Overloading)과 오버라이딩(Overriding)은 메서드의 이름이 같지만 다른 동작을 수행하도록 하는 두 가지 기법입니다.

오버로딩(Overloading): 같은 이름의 메소드를 여러 개 정의하지만 매개변수의 유형과 개수가 다르게 하는 것입니다.
java

class OverloadDemo {
    void test() {
        System.out.println("No parameters");
    }

    // Overload test for one integer parameter.
    void test(int a) {
        System.out.println("a: " + a);
    }

    // Overload test for two integer parameters.
    double test(double a) {
        System.out.println("double a: " + a);
        return a*a;
    }
}

public class Main {
    public static void main(String[] args) {
        OverloadDemo ob = new OverloadDemo();
        double result;
        // call all versions of test()
        ob.test(); 
        ob.test(10); 
        result = ob.test(5.5); 
        System.out.println("Result of ob.test(5.5): " + result);
    }
}


위의 코드에서 test() 메소드는 오버로드되어 세 가지 버전을 가지고 있습니다. 이들은 모두 메서드 이름은 같지만 매개변수의 유형과 개수가 다릅니다.

오버라이딩(Overriding): 부모 클래스에서 상속받은 메소드를 자식 클래스에서 재정의하는 것입니다. 메서드의 이름, 매개변수, 반환 유형이 모두 동일해야 합니다.
java

class Animal {
    void move() {
        System.out.println("Animals can move");
    }
}

class Dog extends Animal {
    // overriding the implementation
    void move() {
        System.out.println("Dogs can walk and run");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal a = new Animal(); // Animal reference and object
        Animal b = new Dog(); // Animal reference but Dog object

        a.move(); // runs the method in Animal class
        b.move(); // runs the method in Dog class
    }
}


위의 코드에서 move() 메소드는 Dog 클래스에서 오버라이딩되어 있습니다. Animal 클래스의 move() 메서드와 이름, 매개변수, 반환 유형이 같지만, Dog 클래스에서는 다른 동작을 수행합니다.

이처럼 오버로딩과 오버라이딩은 모두 메소드의 동작을 다양화하는 데 사용되지만, 오버로딩은 메서드의 매개변수를 변경하여 동작을 달리하고, 오버라이딩은 상속받은 메서드의 동작을 재정의합니다.

 

 

 

 

 

 

자바 오버라이딩과 오버로드 @어노테이션 버전

 

오버로딩(Overloading)과 오버라이딩(Overriding)에 사용하는 어노테이션은 없지만, 

오버라이딩에는 @Override 어노테이션이 존재합니다. 

이 어노테이션은 메소드가 부모 클래스의 메서드를 오버라이드한다는 것을 명시적으로 표시하는 데 사용됩니다. 

오버로딩에는 특별한 어노테이션이 없습니다.

오버로딩(Overloading):
java

class OverloadDemo {
    void test() {
        System.out.println("No parameters");
    }

    // Overload test for one integer parameter.
    void test(int a) {
        System.out.println("a: " + a);
    }

    // Overload test for two integer parameters.
    double test(double a) {
        System.out.println("double a: " + a);
        return a*a;
    }
}

public class Main {
    public static void main(String[] args) {
        OverloadDemo ob = new OverloadDemo();
        double result;
        // call all versions of test()
        ob.test(); 
        ob.test(10); 
        result = ob.test(5.5); 
        System.out.println("Result of ob.test(5.5): " + result);
    }
}


오버라이딩(Overriding):
java

class Animal {
    void move() {
        System.out.println("Animals can move");
    }
}

class Dog extends Animal {
    // overriding the implementation
    @Override
    void move() {
        System.out.println("Dogs can walk and run");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal a = new Animal(); // Animal reference and object
        Animal b = new Dog(); // Animal reference but Dog object

        a.move(); // runs the method in Animal class
        b.move(); // runs the method in Dog class
    }
}


위의 코드에서 @Override 어노테이션은 Dog 클래스의 move() 메소드가 Animal 클래스의 move() 메서드를 오버라이드하는 것을 나타냅니다. 이 어노테이션은 컴파일러에게 이 메서드가 부모 클래스의 메서드를 오버라이드한다는 것을 알려주며, 만약 실제로 오버라이드하는 메서드가 없다면 컴파일 오류를 발생시킵니다. 이를 통해 오버라이딩의 실수를 미리 방지할 수 있습니다.

 

 

 

 

 

 

자바에서 extend 와 implement는 어떤 차이점이 있는가?

 

Java에서 extends와 implements는 클래스와 인터페이스를 활용하는 데 중요한 키워드입니다. 

두 키워드는 상속과 구현을 나타내며, 각각 다음과 같은 특징을 가집니다:

extends: 클래스 간의 상속을 나타냅니다. 부모 클래스의 속성과 메서드를 자식 클래스가 물려받을 수 있게 해 줍니다.
java

class Animal {
    void eat() {
        System.out.println("Eating...");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println("Barking...");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.eat(); // method from Animal class
        d.bark(); // method from Dog class
    }
}


위의 코드에서 Dog 클래스는 Animal 클래스를 확장(extends)하고 있습니다. 따라서 Dog 객체는 Animal 클래스의 메서드인 eat()를 사용할 수 있습니다.



implements: 인터페이스의 메소드를 구현할 때 사용됩니다. 인터페이스는 메서드의 시그니처만 정의하며,

 이를 implements를 사용하여 클래스에서 구현합니다.


java

interface Animal {
    void eat(); // Animals can eat
}

class Dog implements Animal {
    public void eat() {
        System.out.println("Dog is eating...");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.eat(); // method from Animal interface
    }
}


위의 코드에서 Dog 클래스는 Animal 인터페이스를 구현(implements)하고 있습니다. 

따라서 Dog 클래스는 Animal 인터페이스에서 정의된 eat() 메소드를 반드시 구현해야 합니다.

이처럼 extends는 클래스 간의 상속을, implements는 인터페이스의 구현을 나타냅니다. 두 키워드는 서로 다른 용도로 사용되므로, 상황에 따라 적절히 활용해야 합니다.




 

 

 

 

 

 

#개발자취업 #개발자기초 #개발자 #개발자분야 #개발자분류 #개발자종류 #it개발자 #서버개발자 #개발자성장 #신입개발자 #ios개발자 #개발자노트북 #개발자 되는 법 #개발 #앱개발 #웹개발 #개발분야 #it개발 #개발공부 #코딩상식 #개발공부 #개발초보

 

#개발자취업 #개발자면접 #개발자채용 #백엔드개발자 #백엔드개발자 #백엔드개발자취업 #백엔드개발 #프론트엔드개발자 #개발자상담 #백엔드 #개발자 #앱개발자 #웹개발자 #개발자팁 #앱개발자 #백엔드취업 #백엔드공부 #백엔드강의 #백엔드독학

 

#전산직면접 #면접 #면접팁 #면접관 #공공기관전산직면접 #공사면접 #면접질문 #면접할말 #면접준비 #면접준비 #면접답변 #면접질문 #면접기출 #전화면접 #면접복장 #면접답변 #면접꿀팁 #모의면접 #면접후기 #롯데면접 #면접후기 #임원면접 #최종면접 #면접꿀팁

 

 

 

 

 

반응형

댓글