์ค๋ธ์ ํธ ๋์์ธ ์คํ์ผ #1 ๊ฐ์ฒด์งํฅ, ์๋น์ค ์์ฑํ๊ธฐ
by JiwonDevํด๋น ์ฑ ์ ๋ฐํ์ผ๋ก ์ ์๊ฐ์ ์์ด์ ์ ๋ฆฌํ ๊ธ์ ๋๋ค. ํด๋น ์ฑ ์๋ ์๋ ๋ด์ฉ์ด ์ถ๊ฐ๋ก ์์ ์ ์์ต๋๋ค ๐
[ #0. ๊ฐ์ฒด์งํฅ ์ฉ์ด ]
ํด๋น ๊ธ์๋ ์๋์ ๊ฐ์ ์ฉ์ด๋ค์ด ์ฌ์ฉ๋๋ค. ์์ํ ์ฉ์ด๋ค์ด ์๋ค๋ฉด ๊ฐ๋จํ๊ฒ ๋ณด๊ณ ๋์ด๊ฐ์.
- ํด๋์ค(class)์ ๊ฐ์ฒด(object)
โก ๊ฐ์ฒด๋ ์ค์ ๋ก ์กด์ฌํ๋ ์ฌ๋ฌผ, ๊ฐ๋ ์ด๋ฉฐ ํด๋์ค๋ ๊ทธ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ์ฝ๋๋ก ์ ์ ํด ๋์ ๊ฒ์ด๋ค. - ์ํ(State) ๋๋ ์์ฑ(property)
โก ๊ฐ์ฒด๋ ์ํ ๊ฐ(state)๊ณผ ํ์(behavior), ๋ค๋ฅธ ๋ง๋ก ์์ฑ(property)๊ณผ ๊ธฐ๋ฅ(method)์ผ๋ก ๊ตฌ์ฑ๋๋ค.
โก ์์ฑ์ ํฌํจ๋๋ ๊ฒ: ํด๋์ค ๋ฉค๋ฒ ๋ณ์(member variable), ์ธ์คํด์ค ํ๋(filed), ํน์ฑ(attribute), ์ํ(state) - ๋ณ๊ฒฝ๊ฐ๋ฅ(mutable), ๋ณ๊ฒฝ๋ถ๊ฐ๋ฅ(immutable)
โก ์ธ๋ถ์์ ๋ฉ์๋ ๊ฒฐ๊ณผ๊ฐ์ ์ํฅ(side-effect)์ ๋ชป๋ผ์น๊ฒ ๊ฐ์ฒด ์์ฑ์ ๋ถ๋ณ(immutable)ํ๊ฒ ๋ง๋ค ์ ์๋ค. - ํ์(behavior)์ ๋ฉ์๋(method)
โก ๊ฐ์ฒด๊ฐ ๊ฐ์ง ํ์์ด๋ค. ๋ฉ์๋(method), ํจ์(function) - ์์กด์ฑ(dependency)
โก ์ด ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋๋ฐ ํ์ํ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค. ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ํ ์์กด์ฑ(dependency) - ์์(inheritance, extend)
โก ์ดํดํ๊ธฐ ์ฝ๊ฒ ์์์ด๋ผ๋ ์ฉ์ด๋ฅผ ์ฌ์ฉํ์ง๋ง, ๋ฐ์ง๊ณ ๋ณด๋ฉด ๊ฐ์ฒด์ ํ์ฅ(extends)์ด ์ ํํ ์๋ฏธ. - ๊ตฌ์ฑ(composition, is - a)
โก ํํ ์์๊ณผ ๋น๊ต๋๋ ๋ง๋ก์, ๊ฐ์ฒด๋ฅผ ์์ํ์ง ์๊ณ ๋ด ์์ฑ์ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ํ ๋นํ์ฌ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค. - ๋ฐํ(return)๊ณผ ์์ธ(exception)
โก ๊ฐ์ฒด์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋ ํน์ ์์ธ ๊ฐ์ ๋ฐํ(return)ํ๊ฑฐ๋ ์์ธ(throw)๋ฅผ ๋ฐ์์ํค๋๊ฒ ์ผ๋ฐ์ ์ด๋ค. - ๋จ์ํ
์คํธ(unit test)
โก ๊ฐ์ฒด ๋จ์์ ์ ๋ ํ ์คํธ. ํ๊ธ๋ก ๋ฒ์ญํด์ ์กฐ๊ธ ์ด์ํ๋ค. ํ์ํ ์์กด์ฑ์ ํ ์คํธ ๋๋ธ(test double)๋ก ๋์ฒดํ๊ณ ์ค๋น-์คํ-ํ์ธ (Arragne-Act,Assert ๋๋ Given-When-Then)์ผ๋ก ์คํจ ํ ์คํธ๋ฅผ ํ๋์ฉ ๋ง๋ ๋ค. - ํ
์คํธ ๋๋ธ(test double)
โก ์ํ๋ฐฐ์ฐ์ ์คํดํธ ๋๋ธ(stunt double)์์ ๋ฐ์จ ๋ง๋ก, ํ ์คํธ๋ฅผ ์ํด ์ฌ์ฉ๋๋ ์์ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค.
โก ํ ์คํธ ๋๋ธ ๊ฐ์ฒด์๋ Dummy(์๋ฌด๊ฒ๋ ์ํจ), Stub(ํน์ ๊ณ ์ ๊ฐ ๋ฐํ), Fake(์ผ๋ถ๋ง ๋์), Spy(Stub + logging), Mock(ํ๋ก๊ทธ๋๋ฐ๋ ๊ฐ์ง ๊ฐ์ฒด, ์ ์ด๋ ผ ์๋๋ฆฌ์ค๋๋ก ๋์)๋ฑ์ด ์๋ค.
[ #1. ๊ฐ์ฒด๋ก ํ๋ก๊ทธ๋๋ฐ ํ๊ธฐ ]
๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๊ธฐ๋ณธ์ ์ค๋ช
ํ๋ค. ์ด๋ฏธ ์ ์๊ณ ์๋ค๋ฉด ๋ฐ๋ก [ #2 ] ๋ก ๋์ด๊ฐ๋๊ฑธ ์ถ์ฒํ๋ค.
๐ ๊ฐ์ฒด๋ ์ฃผ์ด์ง ํด๋์ค๋ฅผ ๋ฐํ์ผ๋ก ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค.
๊ฐ์ฒด์ ์ ์. ์ด๋ฅผ ๋ค๋ฅธ ๋ง๋ก ๊ฐ์ฒด์ ๋ชจ๋ธ๋ง์ด๋ผ๊ณ ๋ ํ๋ค.
ํด๋์ค ์์, ์ธํฐํ์ด์ค, ๋คํ์ฑ๋ฑ์ ํ์ฉํ์ฌ ๊ฐ์ฒด๋ฅผ ๋ชจ๋ธ๋งํ๊ณ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ฌ ์ฌ์ฉํ๋ค.
public class Person {
private String name;
private int age;
public void eat() {
System.out.println("eat");
}
public void sleep() {
System.out.println("sleep");
}
}
public class Developer extends Person { // ์์์ ์ด์ฉํด ๊ฐ์ฒด๋ฅผ ํ์ฅํ๋ค.
public void coding(){
// Developer ๋ eat, sleep ๋ง๊ณ ๋ coding๊น์ง ๊ฐ๋ฅํ๋ค.
System.out.println("coding");
}
}
๐ ๋ค๋ฅธ ๊ฐ์ฒด์ ์์กด์ฑ์ ์ง์ ๊ฐ์ ธ์ค๊ฑฐ๋ ์์ฑ์๋ก ์ฃผ์ ๋ฐ์ ์ฆ์ ์ฌ์ฉํ๋ค.
class ContentWriter {
FileReader reader; // ํ์ผ์ ์ฝ์ ์ ์๋ FileReader ๊ฐ์ฒด์ ์์กด์ฑ์ด ํ์ํ๋ค.
ContentWriter() {
this.reader = new FileReader("hello.txt");
// ์ด๋ ๊ฒ ๊ฐ์ฒด ์์์ ํ์ํ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ด ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ด๊ธด ํ๋ค.
}
public void print() {
String content = reader.readAll();
System.out.println(content);
}
}
์ด๋ฅผ ์์ฑ์ ์ฃผ์ ์ผ๋ก ๋ฐ๊พธ๋ฉด ์๋์ ๊ฐ๋ค.
์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํจ์ผ๋ก์ [๊ฐ์ฒด ์ค์ ์์ญ]๊ณผ [์๋น์ค ๋ก์ง์์ญ]์ ๋ถ๋ฆฌ์ํฌ ์ ์๊ณ ๊ฐ์ฒด๊ฐ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๋ค.
๊ทธ ๋์ ์์กด์ฑ์ ์ฃผ์ ํด์ฃผ๋ ์ปจํ ์ด๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ผํ๊ณ , ์์กด ๊ด๊ณ๋ฅผ ์ฐพ๊ธฐ ๋ฒ๊ฑฐ๋ฌ์์ง๋ ๋จ์ ์ด ์๋ค.
class ContentWriter {
FileReader reader;
ContentWriter(FileReader reader) {
this.reader = reader;
}
public void print() {
String content = reader.readAll();
System.out.println(content);
}
}
๐ ์์์ ๋ถ๋ชจ ํด๋์ค ๊ตฌํ์ ์ฌ์ ์๋ฅผ, ์ธํฐํ์ด์ค๋ ์ญํ ๊ณผ ์ถ์ํ๋ง ์ ๊ณตํ๋ค.
์์์ ์ด์ฉํ๋ฉด ํด๋์ค๋ฅผ ์ฝ๊ฒ ํ์ฅํ ์ ์๋ค. ๊ทธ๋ฌ๋ ๊ฐ๋ฅํ๋ฉด ์์์ ํผํ ์ ์์ผ๋ฉด ํผํ๋ ๊ฒ์ด ์ข๋ค.
๋น์ฅ์ ์์์ผ๋ก ๊น๋ํ๊ฒ ์ฌ์ฉํ ์ ์์ผ๋ ์๊ตฌ์ฌํญ์ด ์ถ๊ฐ๋๊ณ ์ฝ๋๊ฐ ์์ ๋๋ฉด ๋ถ๋ชจํด๋์ค๊ฐ ๋ฐ๋ ์ ์๋ค.
์ด ์์ ์ผ๋ก ์ธํด ๋ถ๋ชจํด๋์ค์์ ๋ฌธ์ ๊ฐ ์๋๋ผ๋, ์์ ํด๋์ค์์๋ ๋๊ฐ์ด ๋ฌธ์ ๊ฐ ์์์ ๋ณด์ฅํ ์ ์๋ค.
๊ทธ๋์ ๊ฐ์ฒด์งํฅ์ ์์น์ ์ ๋ฐ๋ฅด๊ธฐ์ํด์ , ์ธํฐํ์ด์ค๋ฅผ ๋ง์ด ํ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
๋ฌผ๋ก '์ธํฐํ์ด์ค๊ฐ ๋ฐ๋๊ฑฐ๋' , '๋ถ๋ชจ ๊ฐ์ฒด์ ์ ๋ณด'๊ฐ ํ์ํ ๊ฒฝ์ฐ์๋ ์๊ธฐ ๋๋ฌธ์ ์ธํฐํ์ด์ค๊ฐ ๋ง๋ฅ์ ์๋๋ค.
โก ๊ทธ๋์ ์๋ฐ์์๋ ์ธํฐํ์ด์ค์ ๊ธฐ๋ณธ ๋ฉ์๋(default, private)๋ฅผ ์ ๊ณตํด์ฃผ๋ ๊ฒ์ด๋ค.
โก ๊ฐ์ฒด๋ฅผ ๋ฐ๋ก ์ฌ์ฉํ์ง์๊ณ , ์ธํฐํ์ด์ค๋ฅผ ๊ฑฐ์ณ ์ค์ ๊ฐ์ฒด๋ฅผ ๋ฐ๋ ์์ ์ ์ถ๊ฐ์ ์ธ ๋น์ฉ์ด ๋ ๋ค๋๊ฑธ ์๊ณ ์์.
๐ ๋คํ์ฑ์ ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ์ด์ฉํ ์ ์๋ค. ์ธ์คํด์ค์ ๋ฐ๋ผ ํ์๊ฐ ๋ฌ๋ผ์ง๋ค.
๋คํ์ฑ์ ํต์ฌ์ ์ญํ ๊ณผ ๊ตฌํ์ ๋ถ๋ฆฌ์ด๋ค.
๋คํ์ฑ์ ๊ณ ๋ คํ์ง์๊ณ ๋ฌด์์ ์ธํฐํ์ด์ค๋ก ๋ถ๋ฆฌํ๋ ๊ฑด, ์คํ๋ ค ๋ ์์ข์ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค ์ ์๋ค.
๐ ๊ฐ์ฒด๊ฐ ์์ ์ ์์ฑ์ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ํ ๋นํ๋ ๊ฒ์ ๊ตฌ์ฑ(Composition)์ด๋ผ ํ๋ค.
๐ ๋จ์ ํ ์คํธ๋ '๊ฐ์ฒด' ํ์๋ฅผ ๋ช ์ํ๊ณ ํ์ธํ๋ค. ์์กด์ฑ์ ํ ์คํธ ๋๋ธ๋ก ๋์ฒดํ์.
์ฐธ๊ณ ๋ก ํ ์คํธ ๋๋ธ์ ์ํ๋ฐฐ์ฐ์ ์คํดํธ ๋๋ธ(์คํดํธ ๋์ญ)์์ ๋ฐ์จ ๋ง์ด๋ค. ํ ์คํธ์ฉ ์์ ๊ฐ์ฒด.
[ #2. ์๋น์ค ์์ฑํ๊ธฐ ]
ํ๋ก๊ทธ๋จ์์ ์ฌ์ฉ๋๋ ๊ฐ์ฒด๋ ๋ณดํต 2๊ฐ์ง๋ก ๋๋ ์ ์๋ค. [๋ฐ์ดํฐ๋ฅผ ๋ด๊ณ ์๋ ๊ฐ์ฒด]์ [์์ ์ ์ํํ๋ ์๋น์ค ๊ฐ์ฒด]
[์๋น์ค ๊ฐ์ฒด]๋ ํ๋ฒ ์์ฑํ๋ฉด ์ฌ๋ฌ๋ฒ ์ฌ์ฉํ ์ ์๋ค. ํ์ง๋ง ์์ ์ ๋ฐ๊ฟ ์ ์๊ณ ์๋ช ์ฃผ๊ธฐ๋ ๋จ์ํ๋ค.
[๋ฐ์ดํฐ ๊ฐ์ฒด]๋ ์์ ์ ์ด์ฉํด ์์
์ ์๋ฃํ๋ค. ์๋น์ค๊ฐ ์๋ํ ๋ ์ฌ์ฉํ๋ ์ฌ๋ฃ์ด๋ฉฐ ์๋ช
์ฃผ๊ธฐ๊ธฐ ๋ณต์กํ๋ค.
๐ ์์กด์ฑ๊ณผ ์ค์ ๊ฐ์ ์์ฑ์ ์ธ์๋ฅผ ์ด์ฉํด ๋ช ์์ ์ผ๋ก, ํ๋ฒ์ ์ ๊ณตํ์.
[์ค์ ์์ญ]๊ณผ [์๋น์ค ์์ญ]์ ๋ถ๋ฆฌํ์. ๋๋ก ๊ฐ์ฒด์ ์์กด์ฑ๊ณผ ํจ๊ป ํ์ผ ์ ์ฅ ์์น๋ ํค๊ฐ๋ฑ์ ์ค์ ๊ฐ์ผ๋ก ๊ฐ๊ณ ์์ด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ์ด๋ฌํ ์ค์ ๊ฐ ๋ํ ์์ฑ์ ์ธ์๋ก ์ฃผ์ ๋ฐ์.
class FileLogger {
private String logFilePath;
Formatter formatter;
FileLogger(Formatter formatter, String filePath) {
this.formatter = formatter;
this.logFilePath = filePath; // ์ค์ ๊ฐ์ ์ฃผ์
๋ฐ์ ๊ฐ์ฒด์ ์ญํ ์ ๋๋์.
}
}
* ์์ฑ์๊ฐ ์๋ ์์ ์(Setter)๋ก ์ฃผ์ ํ๋ฉด ์ด๋์์ ์ ์ฃผ์ ๋๋์ง ์ ์ ์๊ณ , ์ค๊ฐ์ ๋ณ๊ฒฝ๋ ๊ฐ๋ฅ์ฑ์ด ์๊ธด๋ค.
๐ ์ง์ด ์๋ ์ค์ ๊ฐ์ ๊ฐ์ฒด๋ก ๋ฌถ์ด์ ์ฃผ์.
์์ด๋์ ํจ์ค์๋์ฒ๋ผ ํญ์ ๊ฐ์ด ๋ค๋๋ ๊ฐ๋ค์ ๋ฐ๋ก ์ฃผ์ ํ๋ฉด ์ฝ๋์ ์์ง๋ ฅ์ด ๋จ์ด์ง๊ณ ๋ถ์ํจ๊ณผ๋ฅผ ๋ฐ์์ํจ๋ค.
์ด๋ฌํ ๊ฐ๋ค์ ๊ฐ์ฒด์ ๋ด์์ ์ ๊ณตํ๋๋ก ํ์.
@Getter
final class UserData {
// ๊ฐ ๊ฐ์ฒด๋ ์์ํ ์ผ์ด ์๋ค.
private String username;
private String password;
}
class ApiClient {
private User user;
// public ApiClient(String username, String password) โ
public ApiClient(User user) {
this.user = user;
}
}
๐ ํ์ํ ๊ฒ์ ์์น(Locate)๊ฐ ์๋๋ผ ํ์ํ ๊ฒ ์์ฒด๋ฅผ ์ฃผ์ ํ๋ผ.
๋๋ถ๋ถ์ ๋ณต์กํ ํ๋ ์์ํฌ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์๋ ๋ชจ๋ ์๋น์ค์ ์ค์ ๊ฐ์ ๊ด๋ฆฌํ๋ ํน๋ณํ ๊ฐ์ฒด๋ฅผ ์ ๊ณตํ๋ค. ํํ ์ด๋ฅผ ์๋น์ค ์์น ์ง์ ์(Service Locator), ๊ฐ์ฒด ๊ด๋ฆฌ์(Manager), ๋ฑ๋ก์(Registry), ์ฑ ์ปจํ ์ด๋(Container)๋ผ๊ณ ๋ถ๋ฅธ๋ค.
๊ทธ๋์ ์ด๋ฌํ ๊ด๋ฆฌ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ค๋ณด๋ฉด ์๋์ ๊ฐ์ ์ ํน์ด ์์ ์ ์๋ค. ์์ ์ปจํ ์ด๋ ์์ฒด๋ฅผ ์ฃผ์ ํด๋ฒ๋ฆฌ๋ ๋ฐฉ๋ฒ.
class HomeController {
private ServiceLocator locator;
public HomeController(ServiceLocator locator) {
this.locator = locator; // ์ธ์ ๋ ์ง ์ฌ์ฉํ ์ ์๊ฒ ์ปจํ
์ด๋๋ฅผ ์์ฒด๋ฅผ ๋ฐ๋๋ค.
}
public void function(){
// ๊ทธ๋ฆฌ๊ณ ์ปจํ
์ด๋๋ฅผ ์ฌ์ฉํด ์๋์ ๊ฐ์ด ๊น๋ํ ์ฝ๋๋ฅผ ์์ฑํ๋ค...?
User user = this.locator.get(EntityManager.className)
.getRepository(User.className)
.getById(request.get('userId'));
...
}
}
์ด ๋ฐฉ๋ฒ์ ๋งค์ฐ ์ข์ง์๋ค.
1. [์๋น์ค] ์์ [์ค์ ์ฝ๋]๋ฅผ ๋ค๋ค์ผ ํ๋ค. ์ ์ด์ User ์์กด์ฑ์ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ์ ์๋น์ค ๊ฐ์ฒด๊ฐ ์์์ผ ํ๋ค.
2. Side Effect ๋ฐ์ โก ํด๋น ์๋น์ค๊ฐ ํ์ํ์ง์๋ ๋ค๋ฅธ ์์กด์ฑ์ ๊ฐ์ ธ์์ ๋ง์๋๋ก ์ฌ์ฉํ ์ ์๋ค.
3. ์๋น์ค ๊ฐ์ฒด๊ฐ ๊ฐ์ง ์์กด์ฑ์ด ๋ฌด์์ธ์ง ์๊ธฐ ์ด๋ ต๋ค. '๋ช ์์ ์ผ๋ก ์์กด์ฑ์ ๊ฐ์ ธ์จ๋ค' ๋ผ๋ ์๋ฏธ๋ฅผ ์๊ฐํด๋ณด๋ผ.
ํ์ํ ๊ฒ์ ์์น(Locator, Container)๋ฅผ ์ฃผ์ ํ์ง ๋ง๊ณ ํ์ํ ๊ฒ ์์ฒด๋ฅผ ์ฃผ์ ํ๋ผ. ๊ทธ๋ผ ๋ชจ๋ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋๋ค.
์์น๋ผ๊ณ ์ ์ ์ด์ ๋ ์ปจํ ์ด๋๋ฟ ์๋๋ผ ๋ชจ๋ ๊ณณ์ ์ ์ฉ๋๋ ๋ง์ด๋ผ์ ๊ทธ๋ ๋ค. ํ์ํ ์์กด์ฑ๋ง์ ์ฃผ์ ํ๋ผ.
class ApiClient {
private User user;
private ResponseFactory responseFactory;
// ์์กด๊ด๊ณ๋ฅผ ๋ช
์์ ์ผ๋ก ์ ์ ์๋ค.
public ApiClient(User user, ResponseFactory responseFactory) {
this.user = user;
this.responseFactory = responseFactory;
}
}
Q. ๊ฐ์ ธ์ค๋ ค๋ ์ปจํ ์ด๋(๋๋ ๊ฐ์ฒด)์ ๋ชจ๋ ๊ธฐ๋ฅ์ด ํ์ํ๋ค๋ฉด์? ์ง์ ์ง์ด์ ์ ๋ฌํ๋ผ๋ฉด์์?
์ด๋ฐ ๊ฒฝ์ฐ๋ ์ ์๋ค. ์ด๋ ์ปจํ ์ด๋๊ฐ ์กด์ฌํ ํ์๊ฐ ์๊ฑฐ๋ ํ ๊ฐ์ฒด๊ฐ ๋๋ฌด ๋ง์ ์ฑ ์์ ์ง๊ณ ์๋ค๋ ์๋ฏธ์ด๋ค.
ํ ๊ฐ์ฒด๊ฐ ๋๋ฌด ๋ง์ ์ฑ ์์ ๊ฐ์ง๊ณ ์์ง ์๋๊ฐ? ๊ฐ์ฒด์ ์ฑ ์์ ๋ถ๋ฆฌํด๋ณด์.
// EntityManager๋ ์ปจํ
์ด๋ ๊ฐ์ฒด์ด๋ค. ์๋์ ์ฝ๋๋ EntityManager์ ๋ชจ๋ ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ค.
user = this.entityManager.getRepository(...).getUser(...);
user.changePassword(newPassword);
this.entityManager.flush();
// ์ด๋ฐ ๊ฒฝ์ฐ์๋ ํ ๊ฐ์ฒด๊ฐ ๋๋ฌด ๋ง์ ์ฑ
์์ ์ง๊ณ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
// EntityManager์ ๋ชจ๋ ๊ธฐ๋ฅ์ ํ ๊ฐ์ฒด๊ฐ ์ฌ์ฉํ ์ผ์ ๊ฑฐ์ ์๋ค.
user = this.entityManager.getRepository(...).getUser(...);
user.changePassword(newPassword);
this.userRepository.save(user) // flush() ์ฑ
์์ ๋ค๋ฅธ ๊ฐ์ฒด๋ก ๋ถ๋ฆฌ
๐ ์๋น์ค๋ ์์ฑ ํ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅ ํด์ผํ๋ค. ๋ฉ์๋์ ํ์๊ฐ ๋ฐ๋๋ฉด ์๋๋ค.
- ์ ํ์ ์ธ ์์กด์ฑ ๊ฐ์๊ฑด ์๋ค. ๋ชจ๋ ์์ฑ์์ ์ธ์๋ ํ์์ฌ์ผ ํ๋ค.
- ์ฆ ์๋น์ค ๊ฐ์ฒด๋ ์์ฑ ํ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅ(immutable)ํ๊ฒ ๋ง๋ค์ด๋ผ.
๊ฐ์ฒด๋ฅผ ๋ถ์์ ํ ์ํ๋ก ์์ฑํ์ง ๋ง๋ผ. null์ ์ฝ์ ํด๋๊ณ ์ค๊ฐ์ setter๋ก ์์กด์ฑ์ ์ถ๊ฐํ๋ ๊ฑด ๋งค์ฐ ์ํํ ํ์์ด๋ค.
์์กด์ฑ์ ํ์ํ๊ฑฐ๋, ํ์ํ์ง ์๊ฑฐ๋ ๋ ์ค ํ๋์ด๋ค. ๋ง์ฝ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด ์๋ฌด๋ฐ ๋์์ ํ์ง ์๋ ๋๋ฏธ(dummy)๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ผ. ์๋น์ค์ ๋์์ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋ง๋ค์ด๋ผ.
final class NullLogger implements Logger {
public void log(String message) {
// ์๋ฌด๋ฐ ๋์๋ ํ์ง ์๋๋ค.
}
}
์๋น์ค๋ ์์ฑ ํ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํด์ผํ๋ค. ๋ง์ฝ ๋ณ๊ฒฝ๋์๋ค๋ฉด ์์ฑ์ ๋ฐ๊ฟ์ ๋ฉ์๋์ ํ์๋ฅผ ๋ฐ๊พธ๋ ๊ฒ ์๋๋ผ, ์๋ก์ด ์๋น์ค ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ๊ฒ์ด ๋ง๋ค.
Q. ๋ง์ฝ ์ธ์คํด์ค๋ง๋ค ๋ค๋ฅธ ์์ ๋ฐ์ดํฐ๊ฐ์ ๊ฐ์ ธ์ผํ๋ค๋ฉด?
๊ทธ๋๋ ์์ฑ์๋ Setter๊ฐ ์๋ ๋ฉ์๋๋ก ์ฃผ์ ๋ฐ๋ ๊ฒ์ด ๋ง๋ค.
[ ์์ ๊ด๋ จ ๋ฐ์ดํฐ ] ๋ ์์กด์ฑ์ด ์๋๋ค. ํ๋๋ก ์ฃผ์ ํ๋ค๋ฉด ๋ชจ๋ ์์ ์ ๋ํด ๋ค์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ด์ผ ํ ๊ฒ์ด๋ค.
final class ContractRepository{
private Session session; // ์ํ ์ ๋ณด๋ฅผ ๊ฐ์ฒด๊ฐ ์์ฑ์ ์ฃผ์
์ผ๋ก ๊ฐ์ง๊ณ ์๋ค.
public ContractRepository(Session session) {
this.session = session;
}
public List getAllContracts(){
return this.select()
// HTTP ์ธ์
์ ์์ฒญ๋ง๋ค ์๋กญ๊ฒ ๋ง๋ค์ด์ง๋ค.
// getAllContracts() ์ ์ธ์คํด์ค ๋ํ ์ฌ์ฌ์ฉ ํ ์์๋ค. ์๋ก ๋ง๋ค์ด์ผ ํ๋ค.
.where([this.session.userId, this.session.companyId])
.getResult();
}
}
์์ ๊ด๋ จ ๋ฐ์ดํฐ๋ ์๋์ ๊ฐ์ด ๋ฉ์๋๋ก ์ฃผ์ ๋ฐ๋ ๊ฒ์ด ๋ง๋ค.
final class ContractRepository{
public ContractRepository() {}
public List getAllContracts(String userId, String companyId){
// ๋ฉ์๋๋ก ์์
๋ฐ์ดํฐ์ ์์กด์ฑ์ ์ฃผ์
๋ฐ๋๋ค.
// ์ด์ ์ด ์๋น์ค ๋ฉ์๋๋ ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
return this.select()
.where([userId, companyId])
.getResult();
}
}
๐ ๋ณต์กํ ํจ์๋ฅผ ๊ฐ์ฒด ์์กด์ฑ์ผ๋ก ๋ฐ๊พธ์ด๋ผ.
๋๋๋ก ์์กด์ฑ์ ํจ์ ์์ ์จ์ด์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
๋ณดํต json_enode() ๋ simplexml_load_file() ๊ฐ์ ์ด๋ฆ์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ด ์ด์ ์ํ๋๋ฐ, ์ด๋ฐ ํจ์๋ค์ ๊ฐ์ธ ๊ฐ์ฒด๋ก ๋ง๋ค๊ณ , ์์กด์ฑ์ ์ฃผ์ ๋ฐ์๋ผ.
์๋น์ค์ ํ์์๋ ์ฝ๋๋ฅผ ์ ๊ฑฐํ๊ณ ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ฐ์ํ๋ ์์ธ๋ ์ค์ ๋ค์ ์ฑ ์์ ๋ถ๋ฆฌํ ์ ์๋ค. ๋ํ ์์กด์ฑ์ ์ ์ฐํ๊ฒ ๊ด๋ฆฌํ์ฌ ์๋น์ค ์ฝ๋์ ์์ ์์ด ๊ธฐ๋ฅ์ ํ์ฅํ ์ ์๋ค.
final class JsonEncoder {
public String encode(...){
try {
json_encode(); // ์์กด์ฑ์ด ์๋ ๋ฉ์๋
} catch (RuntimeException runtimeException) {
// ์ด๋ ๊ฒ ์์ธ๋ฅผ ๊ฐ์ธ ๋ ์์ธํ ์ ๋ณด๋ฅผ ์ ๊ณตํ ์๋ ์๋ค.
throw new RuntimeException("Failed to encode data : " + data);
}
}
}
final class Hello {
private JsonEncoder jsonEncoder;
public Hello(JsonEncoder jsonStringEncoder) {
this.jsonEncoder = jsonStringEncoder; // ์์กด์ฑ์ ์ฃผ์
๋ฐ๋๋ค.
}
public void service(){
this.jsonEncoder.encode(...); // ๊ฐ์ฒด์๊ฒ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ๋ค.
}
}
๋ฌผ๋ก ๊ทธ๋ ๋ค๊ณ String.replace("") ๊ฐ์ ์ธ๋ผ์ธ ํจ์๊น์ง ๋ชจ๋ ๊ฐ์ฒด๋ก ๊ฐ์ธ๋ ๋ณํ ์ง์ ํ๋ผ๋๊ฒ ์๋๋ค.
- ์ด ์์กด์ฑ์ผ๋ก ์ ๊ณตํ ํ์๋ฅผ ๋์ค์ ๋์ฒดํ๊ฑฐ๋ ๊ฐ์ ํ๊ณ ์ถ์๊ฐ?
- ์ด ์์กด์ฑ์ ํ์๊ฐ ๋ณต์กํด์ ๋จ์ง ์ฝ๋ ๋ช ์ค๋ก๋ ํด๊ฒฐํ๊ธฐ ์ด๋ ค์ด๊ฐ?
- ํด๋น ํจ์๋ฅผ ๊ธฐ๋ณธํ์ (primitive) ๊ฐ ๋์ ๊ฐ์ฒด๋ก ์ฒ๋ฆฌํ ์ ์๋๊ฐ?
์ด์ ํด๋นํ๋ค๋ฉด ๊ฐ์ฒด ์์กด์ฑ์ผ๋ก ๋ฐ๊พธ๋ ๊ฒ์ด ์ข๋ค. ์ด๋ ๊ฒํ๋ฉด ์ฑ ์์ ๋ถ๋ฆฌํ ์ ์๊ณ ๋จ์ํ ์คํธํ๊ธฐ ์ฉ์ดํ๋ค๋ ์ฅ์ ๋ ์๊ธด๋ค. ํต์ฌ์ ์ฑ ์์ ๋ถ๋ฆฌ. ์ฆ ์๋น์ค ์ฝ๋๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๊ณ , ์ค์ ์ ๋ณ๊ฒฝ ํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
* ๋จ ์์คํ ํธ์ถ ํจ์๋ ์์ธ์ด๋ค. ์์คํ ํธ์ถ์ ๊ฐ์ฒด๋ก ๊ฐ์ธ์ง ๋ง๊ณ ๋ช ์์ ์ผ๋ก ์ฌ์ฉํด์ผ ์ฌ์ด๋ ์ดํํธ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
๐ ์์ฑ์๋ ์์ฑ์ ํ ๋นํ๊ณ , ์ธ์์ ์ ํจ์ฑ์ ๊ฒ์ฌํ๋ ์ผ์๋ง ์ฌ์ฉํ๋ผ.
์๋น์ค ์์ฑ์ ์ธ์๋ฅผ ์ฃผ์ ํ๊ณ ์ ํจ์ฑ์ ํ์ธํ๋ ์ ์ฐจ์ด๋ค. ์ฆ ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ์ค๋นํ๋ค๋ ๋ป์ด๋ค.
์ค์ ์์ ์ ํด๋น ๊ฐ์ฒด์ ๋ฉ์๋์์ ์ด๋ฃจ์ด์ ธ์ผํ๋ค. ์์ฑ์์์ ์์ ์ ํ์ง๋ง๋ผ.
final class FileLogger implements Logger {
private String logFileDir;
public FileLogger(String logFileDir) {
this.logFileDir = logFileDir;
// ๋๋ ํ ๋ฆฌ๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด ํด๋น ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ๋ค.
if (!is_dir(logFileDir)) {
mkdir(logFileDir, 0777, true);
}
...
}
}
์ด๋ ๊ฒ ์์ฑ์์ ์ ํด์ค์ผํ ์์ ์ด ์๋ค๋ฉด, ์์ฑ์๋ฅผ ๋ณต์กํ๊ฒ ๋ง๋ค์ง ๋ง๊ณ Factory ํด๋์ค๋ฅผ ์ฌ์ฉํด๋ผ.
final class FileLogger implements Logger {
private String logFileDir;
public FileLogger(String logFileDir) {
this.logFileDir = logFileDir;
}
}
final class LoggerFactory{
public static FileLogger createFileLogger(String logFilePath) {
if (!is_dir(logFileDir)) {
mkdir(logFileDir, 0777, true);
}
... // ์ค์ ์์
return fileLogger;
}
}
๋ง์ฝ ์๋์ ๊ฐ์ด Factory ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ๋งคํ ๊ฒฝ์ฐ๋ผ๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
์๋ ์ฝ๋๋ฅผ ์ธ๋ถ์ Factory ํด๋์ค์์ ํ ๋นํ๊ธฐ๋ ์ ๋งคํ๋ค. ํ ๋น ์์๊ฐ ๋ฐ๋๊ฒ ๋๋ฉด ์ค๋ฅ๊ฐ ์ผ์ด๋๊ธฐ ๋๋ฌธ์ด๋ค.
final class Mailer{
private Translator translator;
private String defaultText;
public Mailer(Translator translator, String locale) {
this.translator = translator; // ๋ฐ๋์ translator๋ฅผ ๋จผ์ ํ ๋นํด์ผํ๋ค.
this.defaultText = this.translator.translate("default", locale)
}
}
ํน์ ์์๋ฅผ ์ง์ผ์ ํ ๋นํด์ผ ํ๋ค๋ฉด, ์์ฑ์์๋ ๋ฌด์ธ๊ฐ ์ถ๊ฐ ์์ ์ ํ๊ณ ์๋ค๋ ๋ง์ด๋ค.
์ด๋๋ ๋ด ์ฝ๋์ ์ค๊ณ๊ฐ ์๋ชป๋๊ฒ ์๋๊ฐ ํ๋ฒ ๋ ๊ณ ๋ฏผํด๋ณด์. ์ด ๊ฒฝ์ฐ ์์์ ๋งํ๋ฏ์ด ์ฌ์ฉ์์ ์์น(Locale)์ ๋ณด๋ ๊ฐ์ฒด์ ๋ฐ์ดํฐ์ด๋ค. ์์ฑ์๋ก ์ฃผ์ ๋ฐ๋๊ฒ ์๋๋ผ ๋ฉ์๋ ์ธ์๋ก ์ ๋ฌ๋ฐ๋ ๊ฒ์ด ์ ์ ํ๋ค.
๐ ์ธ์๊ฐ ์ ํจํ์ง ์์ผ๋ฉด ์์ธ๋ฅผ ์ผ์ผ์ผ๋ผ.
์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ๊ฐ ๊ฐ์ฒด์ ์ธ์๋ฅผ ํ์ธํ๋๋ก ๋ง๋ค์ง๋ง๋ผ. ์์ฑ์์ ์ ์ธ์๊ฐ ์ ํจํ์ง ์๋ค๋ฉด ํน์ ๊ฐ์ ๋ฐํํ๋๊ฒ ์๋๋ผ InvalidArgumentException ๊ฐ์ ์์ธ๋ฅผ ์ผ์ผ์ผ ์ฒ๋ฆฌ๋ฅผ ๊ฐ์ ํ๋๋ก ๋ง๋ค์ด๋ผ.
'๐๊ธฐ๋ณธ ์ง์ > Java ๊ธฐ๋ณธ์ง์' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์๋ฐ์ NIO (java.nio) (1) | 2022.03.08 |
---|---|
์๋ฐ์ ๋์์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋์๊ตฌ์กฐ (Atomic, Adder, Accumulator) (0) | 2022.03.08 |
๊ฐ๋น์ง ์ปฌ๋ ํฐ์ TLAB (0) | 2021.09.22 |
JMX ํด, ์๋ฐ ์ดํ๋ฆฌ์ผ์ด์ ๋ชจ๋ํฐ๋ง ๋๊ตฌ (0) | 2021.09.22 |
์๋ฐ์ ์์ฑ์ ๋์๋ฐฉ์ (+Innerํด๋์ค) (0) | 2021.08.22 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev