인터페이스

인터페이스의 메소드는 메소드의 이름과 입출력에 대한 정의만 있고 그 내용은 없다. 그 이유는 인터페이스는 규칙이기 때문이다.

예를들면, USB포트의 규격만 알면 어떤 기기도 만들 수 있다. 또 컴퓨터는 USB 포트만 제공하고 어떤 기기가 만들어지는 지 신경쓸 필요가 없다. 바로 이 점이 인터페이스와 매우 비슷하다.

 

인터페이스 상수와 스태틱 메서드를 활용하여 클래스에서 사용하던 스태틱 메서드와 유사한 목적으로 사용 가능하다.

 

※ 인터페이스의 메소드는 항상 public으로 구현해야 한다.

인터페이스는 인터페이스의 메소드를 반드시 구현해야 하는 "강제성"을 갖는다는 점을 반드시 기억하자.

interface Predator {
		// = public static final
		int sampleCnt = 4;
		void bark();
		// static method in interface
		static int get() {
			return sampleCnt;
		}
}

상속

기존 클래스(base or super)와 새로 만드는 클래스(sub, child)의 관계를 설정하여 코드를 재사용할 수 있다. 베이스 클래스로부터 상속받아서 서브 클래스를 생성하면, 생성된 서브 클래스에서는 베이스 클래스의 모든 멤버를 갖게되고 동일한 인터페이스를 갖는다. 모든 서브 클래스는 베이스 클래스와 같은 타입이 된다.

class Animal {
		protected String name;
		private int age;
	}
	
class Cat extends Animal {
    void sleep() {
        System.out.println(this.name + " zzz");
    }
}
	
class HouseCat extends Cat {
    // method overriding.
    void sleep() {
        System.out.println(this.name + " zzz in house");
    }
}
Cat cat = new Cat();
cat.setName("cat");
cat.setAge(20);
cat.sleep();
System.out.println(cat.getName());

Animal animal = cat;
System.out.println(animal.getName());
// 불가 -> System.out.println(animal.sleep());
HouseCat hCat = new HouseCat();
hCat.setName("hcat");
hCat.sleep();

단, 자바는 다중상속을 지원하지 않는 점에 유의하자!

 

다형성

void barkAnimal(Animal animal) {
      if (animal instanceof Tiger) {
            System.out.println("어흥");
        } else if (animal instanceof Lion) {
            System.out.println("으르렁");
        } else if (animal instanceof Crocodile) {
          System.out.println("쩝쩝");
        } else if (animal instanceof Leopard) {
          System.out.println("캬옹");
        }
    }

위와 같은 메소드는 Animal 클래스를 상속받는 클래스가 증가함에 따라 분기처리가 늘어날 것이다. 이런 경우에 아래처럼 다형성을 활용하면 분기처리를 없앨 수 있고, 보다 명확하게 의미를 전달 할 수 있다.

class Animal {
    protected String name;
    private int age;

    void barkAnimal(Predator pre) {
        pre.bark();
    }
} 

class Cat extends Animal implements Predator{
    void sleep() {
        System.out.println(this.name + " zzz");
    }

    @Override
    public void bark() {
        System.out.println("==== Cat bark");
    }
}

class Dog extends Animal implements Predator {
    @Override
    public void bark() {
        System.out.println("==== Dog bark");
    }
}

참고로 인터페이스는 다중상속을 지원한다.

 

 

추상클래스

추상클래스(Abstract Class)는 인터페이스의 역할도 하면서 클래스의 기능도 가지고 있는 자바의 돌연변이 같은 클래스이다. 추상 클래스에는 abstract 메소드 외에 실제 메소드도 사용할수 있다. 추상클래스는 인터페이스로 대체하는것이 좋은 디자인이라고도 얘기한다.

 

추상 클래스는 인터페이스와는 달리 일반 클래스처럼 객체변수, 생성자, private 메서드 등을 가질 수 있다.

 

※ 추상 클래스는 일반 클래스와는 달리 단독으로 객체를 생성할 수 없다. 반드시 추상 클래스를 상속한 실제 클래스를 통해서만 객체를 생성할 수 있다.

abstract class Animal {
		private int age;
		protected String name;
		
		abstract void printName();
		void print() {
			System.out.println("print " + name);
		}
}
class Cat extends Animal {

    @Override
    void printName() {
        System.out.println("Cat!");
    }
    void print() {
        System.out.println("print child " + name);
    }

}
//불가 -> 구현체가 있어야한다.
//Animal animal = new Animal();

// 추상클래스로도 다형성을 구현가능.
Animal animal = new Cat();

animal.setName("jds");
animal.printName();
// 오버라이딩된다.
animal.print();

Cat cat = new Cat();
cat.setName("jds2");
cat.print();

출처

- https://wikidocs.net/280

 

'프로그래밍 > Java' 카테고리의 다른 글

Java Collection  (0) 2022.01.13
알고리즘 종류 : 스택

괄호의 값

시간제한 메모리 제한
1 초 128 MB

 

문제

4개의 기호 ‘(’, ‘)’, ‘[’, ‘]’를 이용해서 만들어지는 괄호열 중에서 올바른 괄호열이란 다음과 같이 정의된다.

  1. 한 쌍의 괄호로만 이루어진 ‘()’와 ‘[]’는 올바른 괄호열이다. 
  2. 만일 X가 올바른 괄호열이면 ‘(X)’이나 ‘[X]’도 모두 올바른 괄호열이 된다. 
  3. X와 Y 모두 올바른 괄호열이라면 이들을 결합한 XY도 올바른 괄호열이 된다.

예를 들어 ‘(()[[]])’나 ‘(())[][]’ 는 올바른 괄호열이지만 ‘([)]’ 나 ‘(()()[]’ 은 모두 올바른 괄호열이 아니다. 우리는 어떤 올바른 괄호열 X에 대하여 그 괄호열의 값(괄호값)을 아래와 같이 정의하고 값(X)로 표시한다. 

  1. ‘()’ 인 괄호열의 값은 2이다.
  2. ‘[]’ 인 괄호열의 값은 3이다.
  3. ‘(X)’ 의 괄호값은 2×값(X) 으로 계산된다.
  4. ‘[X]’ 의 괄호값은 3×값(X) 으로 계산된다.
  5. 올바른 괄호열 X와 Y가 결합된 XY의 괄호값은 값(XY)= 값(X)+값(Y) 로 계산된다.

예를 들어 ‘(()[[]])([])’ 의 괄호값을 구해보자. ‘()[[]]’ 의 괄호값이 2 + 3×3=11 이므로 ‘(()[[]])’의 괄호값은 2×11=22 이다. 그리고 ‘([])’의 값은 2×3=6 이므로 전체 괄호열의 값은 22 + 6 = 28 이다.

여러분이 풀어야 할 문제는 주어진 괄호열을 읽고 그 괄호값을 앞에서 정의한대로 계산하여 출력하는 것이다. 

 

입력

첫째 줄에 괄호열을 나타내는 문자열(스트링)이 주어진다. 단 그 길이는 1 이상, 30 이하이다.

 

출력

첫째 줄에 그 괄호열의 값을 나타내는 정수를 출력한다. 만일 입력이 올바르지 못한 괄호열이면 반드시 0을 출력해야 한다. 

 

 

예제 입력1

(()[[]])([])

예제 출력1

28

 

예제 입력2

[][]((])

 

예제 출력2

0


public class Main {
	private Stack<Integer> st = new Stack<>();
	
	public static void main(String[] args) throws Exception {
		Main main = new Main();
		main.start();
	}
	private void start() throws Exception {
		System.setIn(new FileInputStream("src/괄호/input.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println(calculate(br.readLine()));
		br.close();
	}
	private int calculate(String in) {
		// 0 : (, 1 : [
		for(int i = 0; i < in.length(); i++) {
			if(in.charAt(i) == '(') {
				st.push(0);
			} else if(in.charAt(i) == ')') {
				Integer subSum = 0;
				boolean isException = true;
				while(!st.isEmpty()) {
					Integer head = st.pop();
					if(head > 1) {
						subSum += head;
					} else {
						isException = false;
						if(head != 0) return 0;
						else {
							st.push(subSum > 0 ? 2*subSum : 2);
							break;
						}
					}
				}
				if(isException) return 0;
			} else if(in.charAt(i) == '[') {
				st.push(1);
			} else if(in.charAt(i) == ']') {
				Integer subSum = 0;
				boolean isException = true;
				while(!st.isEmpty()) {
					Integer head = st.pop();
					if(head > 1) {
						subSum += head;
					} else {
						isException = false;
						if(head != 1) return 0;
						else {
							st.push(subSum > 0 ? 3*subSum : 3);
							break;
						}
					}
				}
				if(isException) return 0;
			}
			
		}
		
		int sum = 0;
		while(!st.isEmpty()) {
			if(st.peek() == 0 || st.peek() == 1) return 0;
			sum += st.pop();
		}
		return sum;
	}
}

 


 

출처

- https://www.acmicpc.net/problem/2504

알고리즘 : 스택

시간 제한 메모리 제한
1초 128MB

 

문제

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” , 그리고 “(()” 는 모두 VPS 가 아닌 문자열이다.

여러분은 입력으로 주어진 괄호 문자열이 VPS 인지 아닌지를 판단해서 그 결과를 YES 와 NO 로 나타내어야 한다. 

 

입력

입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 주어진다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 괄호 문자열이 한 줄에 주어진다. 하나의 괄호 문자열의 길이는 2 이상 50 이하이다. 

 

출력

출력은 표준 출력을 사용한다. 만일 입력 괄호 문자열이 올바른 괄호 문자열(VPS)이면 “YES”, 아니면 “NO”를 한 줄에 하나씩 차례대로 출력해야 한다. 

 

예제입력1

6
(())())
(((()())()
(()())((()))
((()()(()))(((())))()
()()()()(()()())()
(()((())()(

 

예제출력1

NO
NO
YES
NO
YES
NO

 

예제입력2

3
((
))
())(()

 

예제출력2

NO
NO
NO

public class Main {
	private int N;
	private int cnt = 0;
	public static void main(String[] args) throws Exception {
		Main main = new Main();
		main.start();
	}
	private void start() throws Exception{
		//System.setIn(new FileInputStream("src/괄호/input.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		N = Integer.parseInt(br.readLine());
		for(int i = 0; i< N; i++) {
			String in = br.readLine();
			
			bw.write(check(in)? "YES": "NO");
			bw.write("\n");
			cnt = 0;
		}
		bw.close();
		br.close();
	}
	private boolean check(String in) {
		for(int i = 0; i < in.length(); i++) {
			if(in.charAt(i) == '(') {
				cnt++;
				if(cnt > in.length() / 2 ) break;
			} else {
				cnt--;
				if(cnt < 0) {
					break;
				}
			}
		}
		return cnt == 0;
	}
}

 

Redis configuration example

cat redis.conf 
port 6379
cluster-enabled yes
cluster-config-file /data/nodes.conf
cluster-node-timeout 5000
appendonly yes
appendfilename appendonly.aof
dbfilename dump.rdb
logfile /data/log.log

 

cluster-require-full-coverage

yes(default) : slave가 없는 master 노드가 다운되면 cluster 전체가 중지

no : slave가 없는 master 노드가 다운되더라도 cluster는 유지. 다만, 절반 이상의 노드가 다운되면 클러스터는 중지

데이터의 정합성이 중요하다면 yes, 일부 데이터가 유실되어도 괜찮으면 no

cluster-enabled

yes로 하면 cluster mode, no(default)로 하면 standalone mode

cluster-config-file 

클러스터의 상태가 변경될때 마다 상태를 기록

k exec -it redis-cluster-1 -- cat nodes.conf
d4c101ecd86542797df077d945f0329e55cfcd95 10.244.4.73:6379@16379 master - 0 1643072438406 3 connected 10923-16383
dc22da80db3ed3e4f956a53dbe3d527d72c56e87 10.244.4.71:6379@16379 master - 1643072438398 1643072438382 1 connected 0-5460
6a8fbdafa9f4fb0c5f3fa1c0bb943a2b2dc72f5d 10.244.4.77:6379@16379 master - 0 1643072438406 7 connected 5461-10922
c0ffb0eb52b8973a9f321cb6c5559a1b45ed304e 10.244.3.32:6379@16379 myself,slave 6a8fbdafa9f4fb0c5f3fa1c0bb943a2b2dc72f5d 0 1643072438381 7 connected
d197cc2d30c43780a8854bbd75c200c00ea5b417 10.244.4.74:6379@16379 slave d4c101ecd86542797df077d945f0329e55cfcd95 1643072438398 1643072438381 3 connected
85d745b2ff1f791fd5a81b1ba7710a1087ce844f 10.244.4.75:6379@16379 slave dc22da80db3ed3e4f956a53dbe3d527d72c56e87 1643072438398 1643072438382 1 connected
vars currentEpoch 7 lastVoteEpoch 0

cluster-node-timeout(millisecond)

레디스 노드가 다운되었는지 판단하는 시간(default: 15000)

cluster-slave-validity-factor

cluster 노드 다운시 해당 노드의 slave 노드를 마스터로 변경하는 장애 조치를 시작한다. 이때 마스터 노드와 slave 노드 간의 체크가 오랫동안 단절된 상태면 해당 slave는 승격 대상에서 제외된다. 이때 승격 대상에서 제외하는 파단 기준의 시간을 설정한다(default: 10)

계산식 : (cluster-node-timeout * cluster-slave-validity-factor) + repl-ping-slave-period

 

If set to zero, a replica will always consider itself valid, and will therefore always try to failover a master, regardless of the amount of time the link between the master and the replica remained disconnected.

port

방화벽을 사용하고 있다면 기본 포트에 10000을 더한 클러스터 버스 포트도 열려있어야 한다. 예를 들어 기본 포트로 6379를 사용한다면 16379번 포트도 같이 열어야 한다.

daemonize & logfile

no(default) : foreground

yes : background -> 리눅스 프롬프트가 바로 떨어짐(pidfile에 프로세스 id가 저장된다). log file을 지정해서 레디스 서버 로그를 기록하지 않으면 메시지가 날아간다.

 

백업 방식, AOF & RDB 

AOF는 명령이 실행될때 마다 기록되는 파일로서 데이터의 손실이 거의 없다.

RDB 파일은 특정한 간격마다 메모리에 있는 레디스 데이터 전체를 디스크에 쓴다.

  • RDB는 특정 시점의 메모리에 있는 데이터 전체를 바이너리 파일로 저장하는 것이다.
    AOF 파일보다 사이즈가 작다. 따라서 로딩 속도가 AOF 보다 빠르다.
    일반적으로 AOF 가 10초 걸린다면, RDB는 7초 정도로 생각하면 될 것이다.

*AOF를 기본으로 하고, RDB를 Option으로 하는 것을 권장.

*AOF와 RDB 파일 양쪽이 모두 존재할 경우 appendonly yes인 경우에는 레디스 서버 시작시 AOF 파일을 읽어 들이고, no인 경우 RDB 파일을 읽어들인다.

 

AOF configuration

appendonly(default: no)

장애 발생시 메모리에 기록된 데이터가 증발되는데 복구가 가능하도록 디스크에 쓰기 작업을 한다. 기본값으로 appendonly.aof 파일에 기록된다.

 

appendfsync

- always : 명령어 실행시마다 기록

- everysec(default) : 데이터를 모아 1초마다 디스크에 기록

- no : os에 쓰기 시점 처리를 위임

 

auto-aof-rewrite-percentage(0 - 100)

Default : 100

AOF 파일 사이즈가 숫자값 % 이상으로 커지면 rewrite 한다. %의 기준은 레디스 서버가 시작할 시점의 AOF 파일 사이즈를 기준으로 한다. Rewrite를 하면 rewirte 후 파일 사이즈를 기준으로 다시 계산한다.

 

auto-aof-rewrite-min-size

Default : 64mb

AOF 파일 사이즈가 64mb 이하면 rewrite를 하지 않는다. 파일 크기가 작은 경우 rewrite가 자주 발생하는 것을 방지

 

RDB configuration

dbfilename

RDB 파일명을 지정한다.

save

RDB 저장 시점을 지정할 수 있다. number of key modifications per second (Defaut : 900 1)


- http://redisgate.kr/redis/configuration/persistence.php

- https://programmer.help/blogs/redis-configuration-master-slave-cluster.html

- https://redis.io/topics/cluster-tutorial

'빅데이터 > Redis Cluster' 카테고리의 다른 글

Redis 주요 명령어  (0) 2022.02.08
Lettuce Configuration(RedisTemplate)  (0) 2022.02.08
Redis Cluster 장애 복구  (0) 2022.02.08
Redis Cluster Overview  (0) 2022.02.08

+ Recent posts