Design Pattern | Data structure

Observer Pattern

빠빠담 2020. 5. 10. 04:37
반응형

import java.util.Vector;
import java.util.Iterator;
import java.util.Random;

interface Observer {
    // NumberGenerator(관찰대상)가 “나의 내용이 갱신되었습니다.
    // 표시도 갱신해주세요” 라고 관찰자에게 알려줄 때 호출하는 메소드
    // 관찰자들이라면 다 따라야하는 메소드
    public abstract void update(NumberGenerator generator);
}

class DigitObserver implements Observer {
    public void update(NumberGenerator generator) {
        System.out.println("DigitObserver:" + generator.getNumber()); // 관찰한 수를 ‘숫자’로 표시함

        try {
            // 출력한 후, 표시된 모습을 잘 알 수 있도록
            // Thread.sleep( )을 이용하여 스피드를 늦춘다.
            Thread.sleep(100); // (100/1000 = 0.1 초) 동안 CPU를 반환하고 쉬겠다는 뜻
        } catch (InterruptedException e) {
        }
    }
}

class GraphObserver implements Observer {
    // 관찰한 수를 ‘간단한 그래프’로 표시함
    public void update(NumberGenerator generator) {
        System.out.println("GraphObserver:" + generator.getNumber());

        int count = generator.getNumber();

        // count 만큼 별표를 출력한다.
        for (int i = 0; i < count; i++) {
            System.out.print("*");
        }

        System.out.println("");

        try {
            Thread.sleep(100); // (100/1000 = 0.1 초) 동안 CPU를 반환하고 쉬겠다는 뜻
        } catch (InterruptedException e) {
        }
    }
}

class NamePrintObserver implements Observer {
    private String name;

    //생성자. 이름 등록
    public NamePrintObserver(String name) {
        this.name = name;
    }

    // 관찰한 수에 해당하는 name을 출력하여 표시함
    public void update(NumberGenerator generator) {
        System.out.println("NamePrintObserver:" + generator.getNumber());

        int count = generator.getNumber();

        // count 만큼 이름을 출력한다.
        for (int i = 0 ; i < count ; i++) {
            System.out.print(name);
        }

        System.out.println("");

        try {
            Thread.sleep(100); // (100/1000 = 0.1 초) 동안 CPU를 반환하고 쉬겠다는 뜻
        } catch (InterruptedException e) {
        }
    }
}

// 수를 생성하는 클래스, 관찰대상을 대표하는 클래스
abstract class NumberGenerator {
    // NumberGenerator를 관찰하고 있는 Observer들을 보관하고 있는 필드
    private Vector observers = new Vector();

    // Observer를 추가할 때 호출하는 메소드
    public void addObserver(Observer observer) { // Observer를 추가
        observers.add(observer);
    }

    // Observer를 삭제할 때 호출하는 메소드
    public void deleteObserver(Observer observer) { // Observer를 삭제
        observers.remove(observer);
    }

    // Observer 전원에게, “나의 내용이 갱신되었기 때문에
    // 당신의 표시도 갱신해주세요”라고 알려주는 메소드
    public void notifyObservers() {
        Iterator it = observers.iterator();
        // Observer들의 update(this) 메소드를 차례차례 호출한다.

        while (it.hasNext()) {
            Observer o = (Observer) it.next();
            o.update(this);
        }
    }

    public abstract int getNumber(); // 수를 취득한다.

    public abstract void execute(); // 수를 생성한다.
}

// NumberGenerator의 하위 클래스
class PrimeNumberGenerator extends NumberGenerator {
    // java.util.Random 클래스 이용
    private int number; // 생성된 소수를 저장하는 변수

    public int getNumber() { // 수를 취득한다.
        return number; // number 필드의 값을 반환함
    }

    // 3~50 사이의 소수를 20개를 생성하고,
    // 그 때마다 notifyObservers를 호출하여,
    // 관찰자들에게 통지한다.
    public void execute() {
        for(int i = 0 ; i < 20 ; i++) {
            number = getPrimeNumber(50);
            notifyObservers(); // 관찰자에게 통지하라고 요청한다.
        }
    }

    private int getPrimeNumber(int n) {
        int num = -1;

        do {
            //3~n 사이의 소수를 구함
            num = new Random().nextInt(n - 2) + 3;
        } while(!isPrimeNumber(num));

        return num;
    }

    private boolean isPrimeNumber(int n) {
        //소수 확인 로직. 이정도로 했습니다. ㅡㅡ;;
        for(int i = 2 ; i < n ; i++) {
            if(n % i == 0) return false;
        }

        return true;
    }
}

public class Main {
    public static void main(String[] args) {
        // PrimeNumberGenerator 인스턴스 생성
        NumberGenerator png = new PrimeNumberGenerator();

        // PrimeNumberGenerator에 관찰자 3개를 등록함
        png.addObserver(new DigitObserver());
        png.addObserver(new GraphObserver());
        png.addObserver(new NamePrintObserver("NPO!"));

        // PrimeNumberGenerator의 execute( )를 이용해서 수를 생성한다
        png.execute();
        // 소수가 발생될 때마다, 관찰자들은 각자의 방식대로 수를 ‘표시’한다.

    }
}
반응형

'Design Pattern | Data structure' 카테고리의 다른 글

Transactional Outbox Pattern (아웃박스 패턴)  (0) 2023.06.18
[Linked List] 중복값 삭제  (0) 2020.07.08
[Liked List] 단방향 구현  (0) 2020.07.07
[Linked List] 개념  (0) 2020.07.07