โ๐[Backend Development] increase๋ฉ์๋ ์คํ๊ณผ์ ๋ถ์โ
๐ CommentPath ํด๋์ค.
package kobe.board.comment.entity;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Getter
@ToString
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CommentPath {
private String path;
private static final String CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final int DEPTH_CHUNK_SIZE = 5;
private static final int MAX_DEPTH = 5;
// MIN_CHUNK = "00000", MAX_CHUNK = "zzzzz"
private static final String MIN_CHUNK = String.valueOf(CHARSET.charAt(0)).repeat(DEPTH_CHUNK_SIZE);
private static final String MAX_CHUNK = String.valueOf(CHARSET.charAt(CHARSET.length() - 1)).repeat(DEPTH_CHUNK_SIZE);
public static CommentPath create(String path) {
if (isDepthOverflowed(path)) {
throw new IllegalStateException("depth overflowed");
}
CommentPath commentPath = new CommentPath();
commentPath.path = path;
return commentPath;
}
private static boolean isDepthOverflowed(String path) {
return calculateDepth(path) > MAX_DEPTH;
}
private static int calculateDepth(String path) {
// 25๊ฐ์ ๋ฌธ์์ด / 5 = 5depth
return path.length() / DEPTH_CHUNK_SIZE;
}
// CommentPath ํด๋์ค์ path์ depth๋ฅผ ๊ตฌํ๋ ๋งค์๋
public int getDepth() {
return calculateDepth(path);
}
// root์ธ์ง ํ์ธํ๋ ๋งค์๋
public boolean isRoot() {
// ํ์ฌ์ depth๊ฐ 1์ธ์ง ํ์ธํด์ฃผ๋ฉด ๋จ
return calculateDepth(path) == 1;
}
// ํ์ฌ path์ parentPath๋ฅผ ๋ฐํํด์ฃผ๋ ๋งค์๋
public String getParentPath() {
// ๋ 5์๋ฆฌ๋ง ์๋ผ๋ด๋ฉด ๋จ
return path.substring(0, path.length() - DEPTH_CHUNK_SIZE);
}
// ํ์ฌ path์ ํ์ ๋๊ธ์ path์ ๋ง๋๋ ๋งค์๋
public CommentPath createChildCommentPath(String descendantsTopPath) {
if (descendantsTopPath == null) {
return CommentPath.create(path + MIN_CHUNK);
}
String childrenTopPath = findChildrenTopPath(descendantsTopPath);
return CommentPath.create(increase(childrenTopPath));
}
// 00a0z0000200000 <- descendantsTopPath
private String findChildrenTopPath(String descendantsTopPath) {
return descendantsTopPath.substring(0, (getDepth() + 1) * DEPTH_CHUNK_SIZE);
}
private String increase(String path) {
// path์์ ๊ฐ์ฅ ๋ง์ง๋ง 5์๋ฆฌ๋ฅผ ์๋ฅธ ๊ฒ
String lastChunk = path.substring(path.length() - DEPTH_CHUNK_SIZE);
if (isChunkOverflowed(lastChunk)) {
throw new IllegalStateException("chunk overflowed");
}
// Character set์ ๊ธธ์ด
int charsetLength = CHARSET.length();
// lastChunk๋ฅผ 10์ง์๋ก ๋จผ์ ๋ณํํ๊ธฐ ์ํ ๊ฐ์ ์ ์ฅ
int value = 0;
for (char character : lastChunk.toCharArray()) {
value = value * charsetLength + CHARSET.indexOf(character);
System.out.println("value ====> " + value);
System.out.println("CHARSET.indexOf ====> " + CHARSET.indexOf(character));
}
value = value + 1;
String result = "";
for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
result = CHARSET.charAt(value % charsetLength) + result;
value /= charsetLength;
}
return path.substring(0, path.length() - DEPTH_CHUNK_SIZE) + result;
}
private boolean isChunkOverflowed(String lastChunk) {
return MAX_CHUNK.equals(lastChunk);
}
}
โ 1๏ธโฃ ์ฝ๋ ์คํ ํ๋ฆ ํ์ธ
for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
result = CHARSET.charAt(value % charsetLength) + result;
value /= charsetLength;
}
๐ ์ฝ๋ ํต์ฌ ์ญํ
- value๋ฅผ CHARSET(62์ง์) ๊ธฐ๋ฐ์ผ๋ก DEPTH_CHUNK_SIZE(=5) ๊ธธ์ด์ ๋ฌธ์์ด๋ก ๋ณํํ๋ ๊ณผ์
- ๊ฐ ๋ฐ๋ณต์์ value์ ๋ง์ง๋ง ์๋ฆฌ๋ฅผ CHARSET์์ ์ฐพ์ ๋ฌธ์์ด(result)์ ์ถ๊ฐํ๊ณ , value๋ฅผ 62๋ก ๋๋ ์ ๋ค์ ๋ฌธ์๋ฅผ ๊ตฌํจ.
โ 2๏ธโฃ descendantsTopPath = โ00000โ ์ผ ๋ increas(โ00000โ)์ ์คํ ๊ณผ์
๐ increase(โ00000โ) ์คํ ๊ณผ์
1. lastChunk ์ถ์ถ
String lastChunk = path.substring(path.length() - DEPTH_CHUNK_SIZE)
- โ00000โ โ lastChunk = โ00000โ
2. lastChunk๋ฅผ 10์ง์(value)๋ก ๋ณํ
int value = 0;
for (char character : lastChunk.toCharArray()) {
value = value * charsetLength + CHARSET.indexOf(cha)
}
- CHARSET.indexOf(โ0โ) = 0
- value ๊ฐ ๊ณ์ฐ:
value = (0 * 62) + 0 = 0
value = (0 * 62) + 0 = 0
value = (0 * 62) + 0 = 0
value = (0 * 62) + 0 = 0
value = (0 * 62) + 0 = 0
- ์ต์ข ์ ์ผ๋ก value = 0
3. value + 1 ์ฆ๊ฐ.
value = value + 1;
- value = 0 + 1 = 1
4. value๋ฅผ ๋ค์ 62์ง์ ๋ฌธ์์ด๋ก ๋ณํ
for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
result = CHARSET.charAt(value % charserLength) + result;
value /= charsetLength;
}
- ๋ฐ๋ณต ๊ณผ์ (DEPTH_CHUNK_SIZE = 5)
i = 0: value % 62 = 1 โ CHARSET[1] = '1' โ result = "1"
i = 1: value /= 62 = 0 โ CHARSET[0] = '0' โ result = "01"
i = 2: value = 0 โ CHARSET[0] = '0' โ result = "001"
i = 3: value = 0 โ CHARSET[0] = '0' โ result = "0001"
i = 4: value = 0 โ CHARSET[0] = '0' โ result = "00001"
- ์ต์ข result = โ00001โ