7. 진짜 주제
• 소프트웨어 설계에 만병통치약은 없다.
• 단점이 없는 아키텍처란 존재하지 않는다.
• Java-Spring 만 고집하지 말고 그때 그때 상황에 맞는 최선의 선택을 하자.
• 왜 다양한 언어를 꾸준히 배워야 하나?
• 디자인 패턴은 언어 종속적 = 언어마다 문제해결의 방식이 근본부터 다르다.
• Java 에 갇히면 생각도 갇힌다.
• OOP, 정말 제대로 이해하고 있나?
• OOP에서 가장 중요한 사상
• 상속도 아니고, 정보 은닉도 아니고, 추상화도 아니고, 캡슐화도 아니고
• 동적 바인딩 = 늦은 바인딩 = polymorphism 이게 제일로 중요하다.
9. Java8 builder pattern
• 시작하기 전에…
• Builder pattern?
• Foo a = new FooBuilder().setA(111).setB(222).build();
• 등장인물 2명
• Foo class
• FooBuilder class
• 객체 하나 생성하려면 등장인물이 2명 필요합니다.
• 주인공 class
• 빌더 class
10. Java8 builder pattern
• 똑같은 builder 패턴이지만…
• GOF 의 builder 패턴 vs
• Java 언어만의 문법(inner class)를 사용한 builder 패턴 vs
• Java8 언어만의 문법(consumer / provider)를 사용한 builder 패턴
11. Example1.java
public class Example1 {
public static void main(String[] args) {
//Foo 객체를 생성하는 방법 1 : constructor 사용
Foo foo = new Foo("foo", "foo", "foo", "foo",
"foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo");
System.out.println(foo.toString());
//Foo 객체를 생성하는 방법 2 : setter 사용
Foo foo2 = new Foo();
foo2.setA("foo");
foo2.setB("foo");
foo2.setC("foo");
foo2.setD("foo");
// ...귀찮아서 생략
System.out.println(foo2.toString());
}
}
12. Example2.java
public class Example2 {
public static void main(String[] args) {
//FooBuilder classic GOF 방식
Foo foo = new FooBuilder().setA("foo").setB("foo").setC("foo").build();
//FooBuilder 를 java inner class로 정의
BuildableFoo foo2 = new BuildableFoo.fooBuilder().setA("fooA").
setB("fooB").
setC("fooC").
build();
System.out.println(foo.toString());
System.out.println(foo2.toString());
}
}
13. Functional interface 연습
@FunctionalInterface
public interface FunctionalFoo {
void foo();
}
@FunctionalInterface
public interface FunctionalFoo2 {
void foo(int foo);
}
@FunctionalInterface
public interface FunctionalFoo3 {
int foo();
}
14. public class Example0 {
public static void main(String[] args) {
//lambda 표현식을 assign 하려면 functional interface 가 필요
//lambda 표현식의 형태(파라미터, 리턴 타입 등)에 따라 functional interface 도
FunctionalFoo foo = ()->{System.out.println("foo!!");};
FunctionalFoo2 foo2 = (x)->{System.out.println(x);};
FunctionalFoo3 foo3 = ()->{return 100;};
foo.foo();
foo2.foo(777);
System.out.println(foo3.foo());
//function interface 는 예상할 수 있는 형태가 뻔합니다.
//java8 스펙에서 미리 만들어 놓은 interface를 사용해도 됩니다.
Consumer foo4 = (x)->{System.out.println(x);};
foo4.accept(666);
Supplier foo5 = ()->{return 666;};
System.out.println(foo5.get());
Predicate<String> alwaysTrue = (x)->true;
Predicate<String> alwaysFalse = (x)->false;
Predicate<String> isFoo = (x)->x=="foo";
System.out.println(alwaysTrue.and(alwaysFalse).test("foo"));
System.out.println(alwaysTrue.negate().test("foo"));
System.out.println(alwaysTrue.or(alwaysFalse).and(isFoo).test("foo"));
Function<String, Integer> foo7 = (x)->x.length();
Function<Integer, String> lengthToString = (x)->"length: "+x;
System.out.println(foo7.apply("hello foo!!!"));
System.out.println(foo7.andThen(lengthToString).apply("foo"));
}
}
@FunctionalInterface
public interface FunctionalFoo {
void foo();
}
@FunctionalInterface
public interface FunctionalFoo2 {
void foo(int foo);
}
@FunctionalInterface
public interface FunctionalFoo3 {
int foo();
}
15. Example3.java
public class Example3 {
public static void main(String[] args) {
Foo foo = GenericBuilder.of(Foo::new)
.with(Foo::setA, "fooA")
.with(Foo::setB, "fooB")
.with(Foo::setC, "fooC")
.build();
System.out.println(foo.toString());
}
}
16. 동적 바인딩
• 동의어
• 동적 바인딩(Dynamic binding)
• =늦은 바인딩(late binding)
• OOP의 창시자 앨런 케이께서 말하길…
• 내게 있어 OOP란 모든 것(메세징, 지역성, 상태와 흐름에 대한 보호, 은
닉)에 대한 극단적(extreme)인 late binding 을 의미한다.
17. No Silver Bullet
• 만일 소프트웨어의 요구사항이 10개라면
• 그 소프트웨어의 복잡도는 아무리 줄여도 10개
• 최소한 10개의 기능은 반드시 구현을 해야 한다.
• 개발자 놈들이 싸지르는 똥 = 10개 + α
• + α 만 줄여도 성공하는 거다
18. 동적 바인딩
class Bar {
void bark() {
System.out.println("Bar 멍멍멍");
}
}
class NewBar extends Bar {
@Override
void bark() {
System.out.println("NewBar 야옹야옹");
}
}
interface IBar {
void bark();
}
class DogBar implements IBar {
public void bark() {
System.out.println("DogBar 멍멍멍");
}
}
class CatBar implements IBar {
public void bark() {
System.out.println("CatBar 야옹");
}
}
public class Example4 {
public static void main(String[] args) throws Exception {
NewBar a = new NewBar();
//a.bark() 는 compile time에 무슨 일을 할 지 이미 결정
a.bark();
BufferedReader br = new BufferedReader(new InputStreamReader(System
String input = br.readLine();
Bar b = null;
if ("c".equals(input))
b = new NewBar();
else
b = new Bar();
//b.bark() 의 호출이 무슨 일을 할지 결정되지 않음
b.bark();
IBar c = null;
br = new BufferedReader(new InputStreamReader(System.in));
input = br.readLine();
if("c".equals(input))
c = new CatBar();
else
c = new DogBar();
//c.bark() 의 호출이 무슨 일을 할지 결정되지 않음
c.bark();
}
}
19. 정적 바인딩 vs 동적 바인딩
if (open == 파일저장소) {
if(source == 엑셀) {
open엑셀from파일();
} else if (source == 워드) {
open워드from파일();
} else if (source == PPT) {
openPPTfrom파일();
}
} else if (open == 클라우드) {
if(source == 엑셀) {
open엑셀from클라우드();
} else if (source == 워드) {
open워드from클라우드();
} else if (source == PPT) {
openPPTfrom클라우드();
}
}
File foo;
AbstractFileFactory fooFactory;
if (open == 파일저장소)
fooFactory = new LocalFileFactory();
else if (open == 클라우드)
fooFactory = new CloudFileFactory();
if (source == 엑셀)
foo = fooFactory.create(엑셀);
else if (source == 워드)
foo = fooFileFactory.create(워드);
else if (source == PPT)
foo = fooFileFactory,create(PPT);
foo.open();
• 아직은 위력을 잘 모르겠지만…
20. 정적 바인딩 vs 동적 바인딩
if (open == 파일저장소) {
if(source == 엑셀) {
open엑셀from파일();
} else if (source == 워드) {
open워드from파일();
} else if (source == PPT) {
openPPTfrom파일();
} else if (source == hwp) {
openHWPfrom파일();
}
} else if (open == kt클라우드) {
if(source == 엑셀) {
open엑셀from클라우드();
} else if (source == 워드) {
open워드from클라우드();
} else if (source == PPT) {
openPPTfrom클라우드();
} else if (source == hwp) {
openHWPfrom파일();
}
} else if (open == 기타 클라우드) {
if(source == 엑셀) {
open엑셀from클라우드();
} else if (source == 워드) {
open워드from클라우드();
} else if (source == PPT) {
openPPTfrom클라우드();
} else if (source == hwp) {
openHWPfrom파일();
}
}
• 요구사항 추가
• kt 클라우드 추가
• Hwp 포맷 추가
21. 정적 바인딩 vs 동적 바인딩
File foo;
AbstractFileFactory fooFactory;
if (open == 파일저장소)
fooFactory = new LocalFileFactory();
else if (open == kt클라우드)
fooFactory = new KtCloudFileFactory();
else if (open == 클라우드)
fooFactory = new CloudFileFactory();
if (source == 엑셀)
foo = fooFactory.create(엑셀);
else if (source == 워드)
foo = fooFactory.create(워드);
else if (source == PPT)
foo = fooFactory,create(PPT);
else if (source == HWP)
foo = fooFactory,create(HWP);
foo.open();
• 요구사항 추가
• kt 클라우드 추가
• Hwp 포맷 추가
22. 정적 바인딩 vs 동적 바인딩
File foo;
AbstractFileFactory fooFactory;
if (open == 파일저장소)
fooFactory = new LocalFileFactory();
else if (open == kt클라우드)
fooFactory = new KtCloudFileFactory();
else if (open == 클라우드)
fooFactory = new CloudFileFactory();
if (source == 엑셀)
foo = fooFactory.create(엑셀);
else if (source == 워드)
foo = fooFactory.create(워드);
else if (source == PPT)
foo = fooFactory,create(PPT);
else if (source == HWP)
foo = fooFactory,create(HWP);
foo.open();
VS
if (open == 파일저장소) {
if(source == 엑셀) {
open엑셀from파일();
} else if (source == 워드) {
open워드from파일();
} else if (source == PPT) {
openPPTfrom파일();
} else if (source == hwp) {
openHWPfrom파일();
}
} else if (open == kt클라우드) {
if(source == 엑셀) {
open엑셀fromKt클라우드();
} else if (source == 워드) {
open워드fromKt클라우드();
} else if (source == PPT) {
openPPTfromKt클라우드();
} else if (source == hwp) {
openHWPfrom파일();
}
} else if (open == 기타 클라우드) {
if(source == 엑셀) {
open엑셀from클라우드();
} else if (source == 워드) {
open워드from클라우드();
} else if (source == PPT) {
openPPTfrom클라우드();
} else if (source == hwp) {
openHWPfrom파일();
}
}
23. 결론
• 디자인 패턴은 언어 종속적이다.
• OOP의 핵심은 동적 바인딩(=늦은 바인딩)이다.
• 나는 java가 싫어요.