Posts

Showing posts with the label designpattern

design pattern #13 Behavioral pattern - Command

- 툴박스에 쓸 버튼을 하나 만들었다고 치자. 이 버튼을 상속시켜, 여러가지 저장하기, 복사하기, 붙여넣기 등의 버턴을 만든다고 치자. 뭐가 문젠가? - 문제가 충분히 될 수 있다. 일단, subclass 종류가 너무 많다. 그건 그렇다 치더라도, 복사하기가 버튼에만 있는게 아니고. 메뉴에도 있고, 단축기로도 가능하다. 단축기나 메뉴를 버튼에서 상속하자니 말이 안되고, 그렇지 않으려면 중복된 코드가 생기게 된다.  - command 패턴을 레스토랑에 비교했다. 손님이 테이블에서 주문을 하면, 웨이터는 이를 받아 적어 주방 어딘가에 stick note 를 붙여 놓는다. 요리사는 이 목록대로 음식을 만들어서 다시 내놓고. 웨이터는 목록과 음식을 최종 확인 한 뒤 손님에게 가져다준다. - 비즈니스로직과 GUI 분리의 관점에서, 위 상황의 버튼과 기능을 분리하는게 당연하지만, command 패턴이 말하는건 그냥 분리가 아니다. GUI 가 비즈리스 로직에 request 를 바로 보내는 것이 아니라, 따로 분리된 Command 라는 클래스에, 비즈니스 로직에 필요한 데이터들을 모아두고,  Command 라는 클래스에는 이 요청을 수행하는 method 하나가 존재한다. 그러면 GUI 가 비즈니스 로직에 대해 잘 몰라도, Command 만 트리거 하면 된다.  - Command 클래스는 보통 parameters 가 없는 execute method 하나만 가진다. - 그럼 명령 수행에 필요한 매개변수 같은건 어떻게 넘기는가? 아래 예제를 보면,  Command abstract class 에 생성자로  Editor 를 받는데, Editor 자체로 충분하다. 다른 경우에도, 생성자의 매개변수로 넘기고, execute() 함수에서 각 command 별 자세한 처리를 한다.  - Command  패턴은 이렇듯 객체와 할 행동을 같이 묶어 객체로 넘기는데 사용되고, 객체로 넘기기 때문에 serialize 가 가능하고, rev...

design pattern #12 Behavioral pattern - Chain of Responsibility

Chain of Responsibility 는 여러 가지의 기능을 개별 class 에서 구현하고, 이를 연결, 연결, 연결 해서,  client 에서 필요한 chain  을 연결해서 쓸 수 있게 한다.  netty 에서 여러가지 request handler 를 연결해서 쓰는것이 바로 이 패턴이다. 모든 class 는 당연히 동일한 interface 를 구현하고, next chain 으로 넘길지, 바로 처리할지를 구분 할 수 있다. runtime 동적으로 필요한 체인을 원하는 순서대로 연결해서 쓸 수 있고, 잘 쪼개지면 좋은 설계가 된다. 아래 예제는 Middleware 라는  abstract class  안에, Middleware next 라는, 다음 handler 를 담기 위한 변수가 있고,  abstract boolean check() 라는 method 가 각각 구현체에서 구현할 함수이다. linkWith 라는 생성자처럼 생긴 public 함수는, next handler 를 받고 그걸 돌려준다.  abstract check 를 구현하므로, 각각의 handler 는 동일한 parameter 를 받는다. checkNext 함수는 각각의 구현된 check 함수에서 쓰이며, 다음 handler 로 넘길지, 끝낼지를 결정할 수 있다. public abstract class Middleware { private Middleware next ; public Middleware linkWith(Middleware next) { this . next = next; return next; } public abstract boolean check(String email, String password); /** * Runs check on the next object in chain or ends traversing if we're in ...

design pattern #11 Structural pattern - Proxy

API Gateway  느낌의 proxy 가 아니고, 말 그대로 객체(database 연결)  등을 대리하는 proxy pattern 이다. database connection 같은 경우, 무거운 resource 인데, 필요할때 쓰는 lazy initialization 이 좋은데, 이렇게 하면 connection 을 만들어 쓰는 곳마다 lazy initialization 을 해야한다. original service object 와 동일한 proxy 를 만들어, 우리에게 필요한 추가 작업을 해서 필요한 경우에만 실제 object 를 실행하도록 할 수 있다. lazy initialize, 결과를 caching 해두고 쓰거나, access control 을 할 수 있다는 장점이 있다. 클래스 구조가 복잡해지거나,  한번 거쳐가기 때문에 응답에 delay 가 생긴다는 단점이 있다. 코드를 3rd-party  라 바꿀수는 없는데, 추가 기능은 추가해야하는 경우 유용하다. youtube downloader 예제로 보면, 일단 ThirdPartYoutubeLib 가 interface 로 있고, ThirdPartyYoutubeClass 가 이를 구현한다. YoutubeCacheProxy 도 ThirdPartyYoutubeLib 를 구현하는데, ThirdPartyYoutubeLib 를 필드로 갖는다. cache 체크등을 하여 이미 있는 비디오는 cache 에서 리턴하는 등의 예제를 보여준다. 일단 design pattern 을 보면, 모든것은 interface 로부터 시작하는것 같다. 그리고 그를 implement 하고, interface 를 field 로 갖고, 혹은, method 의  return type 이 interface 라거나.  등등이다.  public interface ThirdPartyYouTubeLib { HashMap<String, Video> popularVideos(...

design pattern #10 Structural pattern - Facade

복잡하고 많은 class 들을 사용하여 작업을 하는 경우, client 에게 필요한 기능만을 따로 빼고 나머지는 감춰서 제공하는 class 가 facade class 이다. 사용자 입장에서 복잡도를 낮추고, 필요한 기능만 제공한다는 장점이 있고, 변경이나 라이브러리 대체가 필요한 경우, 이 facade 만 수정 혹은 대체하면 된다는 장점이 있다. facade class 가 어디서든 다 사용되는 god class 가 되어 의존도가 높아지거나, facade class 자체가 커질 위험이 있다는 단점이 있다. 아래 예제를 보면 main  함수에서는 VideoConversionFacade 클래스만 사용하고 있고, 나머지 codec, sound, 등등은 facade 클래스가 처리 한다. public class VideoFile { private String name ; private String codecType ; public VideoFile(String name) { this . name = name; this . codecType = name.substring(name.indexOf( "." ) + 1 ); } public String getCodecType() { return codecType ; } public String getName() { return name ; } } public interface Codec { } public class MPEG4CompressionCodec implements Codec { public String type = "mp4" ; } public class OggCompressionCodec implements Codec { public String type = "ogg" ; } public class CodecFactory { pu...

design pattern #9 Structural pattern - Decorator

이름은 낯설지만, wrapper class 형태로 씌우는것을 말한다 wrapper 로 감싸고, 추가적인 기능을 덧붙인다 추가적인 기능을 덧붙이는데, 상속이 편히 쓸 수 있는 방법인데, 이와같은 wrapper 형식을 통하면, reference 를 가지고 있으며 추가 기능을 붙이고, 필요한 일을 delegate 시킬 수 있다. File 을 Decorate 한다고 치자. interface 로 DataSource 를 만들고, DataSource 를 implement 한 FileDataSource 가 있다. DataSource Decorator  (DataSource Wrapper 라고 이해했다)역시 DataSource 를 implement 한다. Decorator 안에 wrappee 가 있고, 이게 datasource 가 된다. DataSourceDecorator 를 보면, DataSource 를 implement 했는데, wrappee 도 type이 DataSource 이다. 그리고 이 wrapper 를 상속하여 구체 decorator 를 만든게 EncryptDecorator, CompressDecorator 다. 만일 이렇게 하지 않고 상속 한다면, FileDataSource 를 상속 받아, EcryptFileDataSource, CompressFileDataSource 이런식으로 했겠지.  wrapper의 또 장점은,  예제에서처럼,  wrapper 를 한번 더 다른 wrapper 로 감싸는 식으로 할수 있다.  public interface DataSource { void writeData(String data); String readData(); } public class FileDataSource implements DataSource { private String name ; public FileDataSource(String name) { this . name = na...

design pattern #8 Structural pattern - Composite

tree 구조를 ds 가 아닌 object pattern  에서 나타낼때 쓰인다 box 안에 product 가 있거나, box 가 있고 또 그 안에 product 가 있는 경우를 예로 들 수 있다 hierarchy  구조를 표현하는데 유용할 수 있다 디자인패턴의 원리가 그렇듯, client  입장에서 내부 구조를 알 필요가 없다는 장점이 있다 예시에서는, 도형과, 도형 모음을 예로 들고 있다.  일단 공통 기능이 Shape interface 로 묶여있고, 이를 구현 한것이 BasicShape 인데, abstract class 로 되어 있다. BasicShape 을 상속해서 Rect, Circle  등을 만든다. CompoundShape 역시 BasicShape 을 상속 했는데, List<Shape> 을 가지고 있다. 예제에는 ImageEditor 라는 class 가 별도로 있고, 여기서 CompoundShape 을 가지고 있어, main 에서 쓰고 있다. 한눈에  와 닿지는 않지만, interface 를 abstract basic class 로 implement  하고, 이를  상속받아 구체적인 class 를 쓰는 경우는 좀 본것 같다. public interface Shape { int getX(); int getY(); int getWidth(); int getHeight(); void move( int x, int y); boolean isInsideBounds( int x, int y); void select(); void unSelect(); boolean isSelected(); void paint(Graphics graphics); } abstract class BaseShape implements Shape { public int x ; public int y ; public...