TIL

[TIL/정처기] 2025/03/19

23년 3회 기출 코드 정리 ✍️23-3-1-JAVA ⚙️SuperObject a = new SubObject();에서 a.paint()는 부모의 paint()를 호출하며, 다형성에 의해 오버라이딩된 자식의 draw()를 호출하게 되어 "B", "D", "C", "D"

2025년 3월 19일8min read

23년 3회 기출 코드 정리 ✍️

23-3-1-JAVA ⚙️

code
class SuperObject {
    public void draw(){
        System.out.println("A");
        draw();
    }
    public void paint(){
        System.out.print("B");
        draw();
    }
}

class SubObject extends SuperObject {
    public void paint(){
        super.paint();
        System.out.print("C");
        draw();
    }
    public void draw(){
        System.out.print("D");
    }
}

public class Test {
    public static void main(String[] args) {
        SuperObject a = new SubObject();
        a.paint();
        a.draw();
    }
}

SuperObject a = new SubObject();에서 a.paint()는 부모의 paint()를 호출하며, 다형성에 의해 오버라이딩된 자식의 draw()를 호출하게 되어 "B", "D", "C", "D"가 출력된다. 이후 a.draw()는 자식의 오버라이딩된 draw()를 호출하여 "D"가 출력된다. 따라서 최종 출력 결과는 BDCDD이다.

23-3-3-C ⚙️

code
#include <stdio.h>

main(){
    char* p = "KOREA";
    printf("1. %s\n", p);
    printf("2. %s\n", p + 1);
    printf("3. %c\n", *p);
    printf("4. %c\n", *(p + 3));
    printf("5. %c\n", *p + 4);
}

char p = "KOREA";에서 p는 문자열 "KOREA"의 첫 번째 문자를 가리킨다. 1. ``%s\n``에 의해 "KOREA" 전체 출력. 2. p + 1은 'O'부터 시작하므로 "OREA" 출력. 3. p는 'K'를 가리켜 ``%c\n``에 의해 'K' 출력. 4. (p + 3)은 'E'를 가리켜 'E' 출력. 5. p + 4는 'K'(ASCII 75)에 4를 더해 'O'(ASCII 79) 출력.

5번이 헷갈릴 수 있는데, ``p``는 기본적으로 알파벳 'K'이고, 알파벳에 숫자를 더하면 더한 숫자 만큼의 다음 알파벳 문자를 의미한다.

23-3-4-C ⚙️

code
#include <stdio.h>

struct insa {
    char name[10];
    int age;
    struct insa* impl_a;
    struct insa* impl_b;
}

main(){
    struct insa p1 = {"Kim", 28, NULL, NULL};
    struct insa p2 = {"Lee", 36, NULL, NULL};
    struct insa p3 = {"Park", 41, NULL, NULL};
    p1.impl_a = &p2;
    p2.impl_b = &p3;
    printf("%s\n", p1.impl_a -> name);
    printf("%d", p2.impl_b -> age);
}

구조체 포인터를 사용한 연결에 관한 코드. ``->``는 구조체 포인터를 통해, 구조체 멤버에 접근하는 구조체 포인터 연산자라는 점을 기억하면 된다.

23-3-9-C ⚙️

code
#include <stdio.h>

int isPerfectNum(int num){
    int sum = 0;
    for(int i = 1; i < num; i++){
        if(num % i == 0){
            sum += i;
        }
    }
    if(num == sum) return 1;
    else return 0;
}

main(){
    int r = 0;
    for(int i = 1; i <= 100; i++){
        if(isPerfectNum(i))
        r += i;
    }
    printf("%d", r);
}

완전수에 대해 알면 쉽게 이해되는 코드. 완전수란, 자기 자신을 제외한 약수들의 합이 자기 자신과 같은 수를 의미한다. ``num % i`는 현재 숫자가 num의 약수인지를 묻는 코드다. `sum`은 자기 자신을 제외한 약수들의 합을 의미한다. 즉, 최종적으로 출력하는 `r`은 100 이하의 완전수 6, 28의 합인 34이다. 완전수에는 `6, 28, 496``이 있다는 점을 알아두자.

23-3-12-JAVA ⚙️

code
class Person {
    private String name;
    public Person(String val){
        name = val;
    }
    public static String get(){
        return name;
    }
    public void print(){
        System.out.println(name);
    }
}

public class Test {
    public static void main(String[] args) {
        Person obj = new Person("Kim")
        obj.print();
    }
}

오류가 발생하는 라인을 찾는 코드.

static 메소드는 클래스에 속하는 메소드다. 객체를 생성하지 않고도 클래스의 이름으로 직접 호출할 수 있다. 그런데 name은 인스턴스 변수다. 인스턴스 변수는 객체에 속하는 변수이고, 클래스에서 객체를 생성할 때마다 각각의 객체가 독립적으로 가지는 변수라고 할 수 있다.

static 메소드는 객체의 인스턴스 변수에 직접 접근할 수 없다. 따라서 ``get() 함수의 return name;`` 라인에서 오류가 발생하게 된다.

23-3-14-JAVA ⚙️

code
class P {
    public int calc(int n){
        if(n <= 1) return n;
        return calc(n - 1) + calc(n - 2);
    }
}

class C extends P {
    public int calc(int n){
        if(n <= 1) return n;
        return calc(n - 1) + calc(n - 3);
    }
}

public class Test {
    public static void main(String[] args) {
        P obj = new C();
        System.out.print(obj.calc(7));
    }
}

C 클래스의 생성자를 이용하여 P 클래스의 객체 변수 obj를 생성했기에, obj.calc()에서의 calc()는, C의 calc()이다. 즉 ``calc(n - 1) + calc(n - 3)``에 대한 연산이 반복된다. 최종 출력 결과는 2.

23-3-15-C ⚙️

code
#include <stdio.h>

int f(int n){
    if(n <= 1) return 1;
    else return n * f(n - 1);  
}

main(){
    printf("%d", f(7));
}

재귀 함수에 관한 코드. 궁극적으로 7 팩토리얼 값을 출력하는 코드라고 볼 수 있다. 최종 출력 결과는 5040.

23-3-16-Python ⚙️

code
x, y = input("x, y의 값을 공백으로 구분하여 입력 : ").split(' ')
print("x의 값 :", x)
print("y의 값 :", y)

split 메소드를 통해 공백을 기준으로 x와 y의 값을 받는 코드. 특정 값을 기준으로 구분할 때 split 메소드를 사용한다는 점을 기억하면 된다.

이론 문제 포인트 ✍️

1. 디자인 패턴 ✅ - 모듈 간의 관계 및 인터페이스를 설계할 때 참조할 수 있는 전형적인 해결 방식 또는 예제 - GOF의 디자인 패턴은 생성 / 구조 / 행위 패턴으로 구분됨

2. 생성 패턴 ✅ - Creational Pattern, 클래스나 객체의 생성과 참조 과정을 정의하는 패턴 - ``추상 팩토리(Abstract Factory)``: 구체적인 클래스에 의존하지 않고, 인터페이스를 통해 서로 연관, 의존하는 객체들의 그룹으로 생성하여 추상적으로 표현하는 패턴. 연관된 서브 클래스를 묶어 한 번에 교체하는 것이 가능함

- ``빌더(Builder)``: 작게 분리된 인스턴스를 건축 하듯이 조합하여 객체를 생성하는 패턴. 객체의 생성 과정과 표현 방법을 분리하고 있어, 동일한 객체 생성에서도 서로 다른 결과를 만들어 낼 수 있음

- ``팩토리 메소드(Factory Method)``: 객체 생성을 서브 클래스에서 처리하도록 분리하여 캡슐화한 패턴. 상위 클래스에서 인터페이스만 정의하고 실제 생성은 서브 클래스가 담당함

- ``프로토타입(Prototype)``: 원본 객체를 복제하는 방법으로 객체를 생성하는 패턴

- ``싱글톤(Singleton)``: 하나의 객체를 생성하면 생성된 객체를 어디서든 참조할 수 있지만, 여러 프로세스가 동시에 참조할 수는 없는 패턴. 클래스 내에서 인스턴스가 하나뿐임을 보장하며, 불필요한 메모리 낭비를 최소화 할 수 있음

3. 구조 패턴 ✅ - Structural Pattern, 구조가 복잡한 시스템을 개발하기 쉽도록 클래스나 객체들을 조합하여 더 큰 구조로 만드는 패턴

- ``어댑터(Adapter)``: 호환성이 없는 클래스들의 인터페이스를 다른 클래스가 이용할 수 있도록 변환해주는 패턴. 기존의 클래스를 이용하고 싶지만 인터페이스가 일치하지 않을 때 이용

- ``브리지(Bridge)``: 구현부에서 추상층을 분리하여 서로가 독립적으로 확장할 수 있도록 구성한 패턴. 기능과 구현을 두 개의 별도 클래스로 구현함

- ``컴포지트(Composite)``: 여러 객체를 가진 복합 객체와 단일 객체를 구분 없이 다루고자 할 때 사용하는 패턴. 객체들을 트리 구조로 구성하여 디렉터리 안에 디렉터리가 있듯이 복합 객체 안에 복합 객체가 포함되는 구조를 구현할 수 있음

- ``데코레이터(Decorator)``: 객체 간의 결합을 통해 능동적으로 기능들을 확장할 수 있는 패턴. 임의의 객체에 부가적인 기능을 추가하기 위해 다른 객체들을 덧붙이는 방식으로 구현함

- ``퍼싸드(Facade)``: 복잡한 서브 클래스들을 피해 더 상위에 인터페이스를 구성함으로써 서브 클래스들의 기능을 간편하게 사용할 수 있도록 하는 패턴. 서브 클래스들 사이의 통합 인터페이스를 제공하는 Wrapper 객체가 필요함

- ``플라이웨이트(Flyweight)``: 인스턴스가 필요할 때마다 매번 생성하는 것이 아니고 가능한 한 공유해서 사용함으로써 메모리를 절약하는 패턴. 다수의 유사 객체를 생성하거나 조작할 때 유용하게 사용할 수 있음

- ``프록시(Proxy)``: 복잡한 시스템을 개발하기 쉽도록 클래스나 객체들을 조합하는 패턴. 내부에서는 객체 간의 복잡한 관계를 단순하게 정리해 주고, 외부에서는 객체의 세부적인 내용을 숨겨주는 역할을 수행함

4. 행위 패턴 ✅ - Behavioral Pattern, 클래스나 객체들이 서로 상호작용하는 방법이나 책임 분배 방법을 정의하는 패턴

- ``책임 연쇄(Chain of Responsibility)``: 요청을 처리할 수 있는 객체가 둘 이상 존재하여, 한 객체가 처리하지 못하면 다음 객체로 넘어가는 형태의 패턴

- ``커맨드(Command)``: 요청을 객체의 형태로 캡슐화하여 재이용하거나 취소할 수 있도록 요청에 필요한 정보를 저장하거나 로그에 남기는 패턴. 요청에 사용되는 각종 명령어들을 추상 클래스와 구체 클래스로 분리하여 단순화함

- ``인터프리터(Interpreter)``: 언어에 문법 표현을 정의하는 패턴. SQL이나 통신 프로토콜과 같은 것을 개발할 때 사용함

- ``반복자(Iterator)``: 자료 구조와 같이 접근이 잦은 객체에 대해 동일한 인터페이스를 사용하도록 하는 패턴. 내부 표현 방법의 노출 없이 순차적인 접근이 가능함

- ``중재자(Mediator)``: 수많은 객체들 간의 복잡한 상호작용을 캡슐화하여 객체로 정의하는 패턴. 객체 사이의 의존성을 줄여 결합도를 감소시킬 수 있음

- ``메멘토(Memento)``: 특정 시점에서의 객체 내부 상태를 객체화함으로써 이후 요청에 따라 객체를 해당 시점의 상태로 돌릴 수 있는 기능을 제공하는 패턴

- ``옵서버(Observer)``: 한 객체의 상태가 변화하면 객체에 상속되어 있는 다른 객체들에게 변환된 상태를 전달하는 패턴. 일대다의 의존성을 정의하며, 주로 분산된 시스템 간에 이벤트를 생성/발행하고, 이를 수신해야 할 때 이용함

- ``상태(State)``: 객체의 상태에 따라 동일한 동작을 다르게 처리해야 할 때 사용하는 패턴. 객체 상태를 캡슐화하고 이를 참조하는 방식으로 처리함

- ``전략(Strategy)``: 동일한 계열의 알고리즘들을 개별적으로 캡슐화하여 상호 교환할 수 있게 정의하는 패턴. 클라이언트는 독립적으로 원하는 알고리즘을 선택하여 사용할 수 있으며, 클라이언트에 영향 없이 알고리즘의 변경이 가능함

- ``템플릿 메소드(Template Method)``: 상위 클래스에서 골격을 정의하고, 하위 클래스에서 세부 처리를 구체화하는 구조의 패턴. 유사한 서브 클래스를 묶어 공통된 내용을 상위 클래스에서 정의함으로써 코드의 양을 줄이고 유지보수를 용이하게 함

- ``방문자(Visitor)``: 각 클래스의 데이터 구조에서 처리 기능을 분리하여 별도의 클래스로 구성하는 패턴. 분리된 처리 기능은 각 클래스를 방문하여 수행함

5. EAI ✅ - Enterprise Application Integration, 기업 내 각종 애플리케이션 및 플랫폼 간의 정보 전달, 연계, 통합 등 상호 연동이 가능하게 해주는 솔루션

- ``Point-to-Point``: 가장 기본적인 애플레케이션 통합 방식. 애플리케이션을 1:1로 연결하고, 변경 및 재사용이 어려움

- ``Hub & Spoke``: 단일 접점인 허브 시스템을 통해 데이터를 전송하는 중앙 집중형 방식. 확장 및 유지 보수가 용이하나, 허브 장애 발생 시 시스템 전체에 영향을 미침

- ``Message Bus``: 애플리케이션 사이에 미들웨어를 두어 처리하는 방식. 확장성이 뛰어나며 대용량 처리가 가능함

- ``Bus Hybrid``: Hub & Spoke와 Message Bus의 혼합 방식. 그룹 내에서는 Hub & Spoke 방식을, 그룹 간에는 Message Bus 방식을 사용함

6. JSON ✅ - JavaScript Object Notation, 데이터 객체를 속성, 값의 쌍 형태로 표현하는 개방형 표준 포맷 - 비동기 처리에서 사용되는 AJAX에서 XML을 대체하여 사용되고 있음

7. AJAX ✅ - Asynchronous JavaScript and XML, 자바스크립트를 사용하여 클라이언트와 서버 간에 XML 데이터를 주고 받는 비동기 통신 기술 - 전체 페이지를 새로 고치지 않고도 웹 페이지 일부 영역만을 업데이트 할 수 있음

8. IPsec / SSL / S-HTTP ✅

- ``IPsec(IP Security)``: 네트워크 계층에서 IP 패킷 단위의 데이터 변조 방지 및 은닉 기능을 제공하는 프로토콜. 암호화와 복호화가 모두 가능한 양방향 암호화 방식을 사용함

- ``SSL(Secure Sockets Layer)``: TCP/IP 계층과 애플리케이션 계층 사이에서 인증, 암호화, 무결성을 보장하는 프로토콜

- ``S-HTTP(Secure Hypertext Transfer Protocol)``: 클라이언트와 서버 간에 전송되는 모든 메세지를 암호화하는 프로토콜

9. 인터페이스 구현 검증 도구 ✅

- ``xUnit``: 같은 테스트 코드를 여러 번 작성하지 않게 도와주며, 테스트마다 예상 결과를 기억할 필요가 없게 하는 자동화된 해법을 제공하는 단위 테스트 프레임워크

- ``STAF``: 서비스 호출 및 컴포넌트 재사용 등 다양한 환경을 지원하는 테스트 프레임워크. 크로스 플랫폼이나 분산 소프트웨어에서 테스트 환경을 조성할 수 있도록 지원하며, 분산 소프트웨어의 경우 각 분산 환경에 설치된 데몬이 프로그램 테스트에 대한 응답을 대신하며, 테스트가 완료되면 이를 통합하고 자동화하여 프로그램을 완성함

- ``FitNesse``: 웹 기반 테스트 케이스 설계, 실행, 결과 확인 등을 지원하는 테스트 프레임워크

- ``NTAF``: FitNesse의 장점인 협업 기능과 STAF의 장점인 재사용 및 확장성을 통합한 NHN(Naver)의 테스트 자동화 프레임워크

- ``Selenium``: 다양한 브라우저 및 개발 언어를 지원하는 웹 애플리케이션 테스트 프레임워크

- ``watir``: 인터프리터 방식의 객체 지향 스크립트 언어인 Ruby를 사용하는 애플리케이션 테스트 프레임워크

10. UI / UX ✅

- ``UI(User Interface)``: 사용자와 시스템 간의 상호작용이 원할하게 이뤄지도록 도와주는 장치나 소프트웨어

- ``UX(User Experience)``: 사용자가 시스템이나 서비스를 이용하면서 느끼고 생각하게 되는 총체적인 경험