[OOP] 디자인 원리 - Head First-OOAD

Programming/Design Patterns 2007.08.28 07:35
『Head First Object-Oriented Analysis&Design』 책의 내용 중에 8장에서 다루고 있는 디자인 원리에 관한 좋은 내용이 있어서 소개한다.

여담 : 여러분들 마우스 옆에 핸드폰 놓지 맙시다. 자꾸 헷갈리네…쿠쿠

일단 와 닫는 짧은 문장 하나, “모방은 바보 같은 짓을 하지 않기 위한 가장 진지한 방안입니다.” 이 이야기는 새롭고 독창적인 방법이 좋을 수 있으나 그 방법은 기존에 같은 문제를 해결한 것이 없거나 자신의 독창적인 방법이 나은 결과를 가져왔을 때만 유효한 해결책이라는 설명이다. 이런 비슷한 내용은 디자인 패턴 관련 책에서 주로 다루고 있는데 이미 입증된 것이 항상 옳은 방법일 수는 없으나 가장 안전한 방법일 듯 싶다.

디자인 원리 : 디자인 원리는 코드를 좀 더 유지보수하기 쉽고, 유연하고, 확장하기 쉽게 만들기 위해, 코드의 작성이나 디자인에 적용되는 기본 도구 또는 기법이다.

객체지향 원리
1.    변하는 것을 캡슐화하라.
2.    구현에 의존하기 보다는 인터페이스에 의존하도록 코딩하라.
3.    각 클래스는 변경 요인이 오직 하나이어야 한다.
4.    클래스는 행동과 기능에 관한 것이다.

위와 같은 디자인 원리에 대한 구체적인 내용을 살펴보면 아래와 같다.

원리 1)
개방-폐쇄의 원리 OCP(Open-Closed Principle)

클래스는 확장에는 열려 있고, 수정에는 닫혀 있어야 한다는 것으로 보통 추상클래스의 확장과 override 개념에서 찾을 수 있을 듯싶다. 추상 클래스(상위 클래스) 자체는 하나의 독립되고 완전한 기능을 수행하며 수정에 닫혀 있고 그 추상 클래스를 확장하는 클래스에서 개별적으로 필요한 기능은 오버라이드를 통해서 고유의 기능을 수행할 수 있도록 하는 개념을 의미한다.

Java에서는 파라미터의 형태, 파라미터의 개수, 메소드의 접근성이 다를 경우에는 전혀 다른 메소드로 인식할 수 있다. 이 때문에 private로 선언된 함수를 사용하되 그 함수와 다른 기능을 수행하는 같은 메소드명의 public 메소드를 새로 만들어 외부에서 접근할 수 있도록 하는 경우도 이 OCP원리에 부합되는 예라고 할 수 있다.

원리 2)
반복 금지의 원리 DRY(Don’t Repeat Yourself)

공통되는 부분을 추출하여 추상화하고 한 곳에 두어 중복 코드를 피하라는 내용이다. 책에서는 2장에서 설명한 강아지 문(외국의 전원주택을 보면 애완견이 스스로 출입할 수 있도록 현관문 아래에 작은 문을 달아놓은 것을 프로그래밍한 내용)에 대한 이야기로 개념을 설명하고 있는데 리모컨을 눌렀을 때 열려있던 문은 닫히고 닫혀있던 문은 여는 기능을 수행한다. 또한 문은 리모컨 뿐만이 아니라 강아지가 짖는 소리에도 열린다. 그리고 열려있던 문은 일정한 시간이 지나면 자동으로 닫게 설계되어 있는데 이때 일정한 시간이 흐르면 자동으로 닫히는 기능을 리모컨 기능에도 넣고 강아지가 짖는 것을 판별하는 기능에도 넣었을 때 코드가 중복되는 것을 강아지 문 하나에 넣어 문이 open 되었을 때 일정 시간이 지나면 닫히게 할 수 있다는 것이다. 강아지 문을 여는 행위를 지시하는 곳은 두 곳이지만 이 두 곳 모두 일정 시간이 지나면 자동으로 닫히는 기능을 넣는 중복을 피하고 그 행위를 하는 강아지 문에 기능을 넣는 것이 좋다는 것이다. 하나의 요구사항은 한 곳에 두어 코드 중복으로 인한 유지보수의 어려움을 없애야 한다는 내용이다.

원리 3)
단일 책임의 원리 SRP(Single Responsibility Principle)

시스템의 모든 객체는 하나의 책임만을 가지며, 객체가 제공하는 모든 서비스는 그 하나의 책임을 수행하는 데 집중되어 있어야 한다는 내용이다. 이는 얼핏 보면 반복 금지의 원리와 비슷하다고 볼 수 있는데, 반복금지의 원리는 SRP를 포괄하는 내용이라고 볼 수 있다. 반복금지의 원리는 하나의 기능을 한 곳에 두자는 내용으로 그 한 곳이 클래스가 될 수도 있고 코드가 될 수도 있다. 하지만 SRP는 클래스가 한 가지 일만 잘하게 하자는 내용이다.

책에서는 간단하면서도 재미있는 방법을 제한하고 있는데 아래와 같은 방법이다.

[*]이 자신을 [*]한다.를 한 줄에 하나씩 작성하고 첫 번째 빈칸에는 자신 클래스명을 기입하고 두 번째 빈칸에는 자신 클래스에서 사용하고 있는 메소드명을 기입하는 것이다. 이렇게 작성하여 한 줄씩 큰 소리로 읽어보면 ‘무엇이 자신을 무엇 한다’는 말이 맞지 않은 경우가 SRP를 위반할 가능성이 높다는 이야기다. 예를 들면 다음과 같다.

Automobile 이라는 클래스에 아래와 같은 메소드들이 있다고 가정하면
1.    start()
2.    stop()
3.    changeTires(Tire[*])
4.    drive()
5.    wash()
6.    checkOil()
7.    getOil():int

1.    [Automobile]이(가) 자신을 [start](출발한다).
2.    [Automobile]이(가) 자신을 [stop](멈춘다).
3.    [Automobile]이(가) 자신을 [changeTires](타이어를 간다).
4.    [Automobile]이(가) 자신을 [drive](운전한다).
5.    [Automobile]이(가) 자신을 [wash](닦는다).
6.    [Automobile]이(가) 자신을 [checkOil](오일을 점검한다).
7.    [Automobile]이(가) 자신을 [getOil](기름을 얻는다).

위와 같이 썼을 때 책에서는 3개의 메소드는 SRP를 따르고 있고 나머지 4개의 경우에는 SRP를 따르지 않고 있다고 이야기 하고 있다. 다시 말해서 3개의 메소드는 Automobile 클래스에 있어야 하지만 나머지 4개의 메소드는 따로 빼내어 다른 클래스로 만들어야 단일 책임의 원리를 따를 수 있다는 이야기다.

답은 며칠 후에 이 포스트에 추가로 올려놓도록 할 테니 여러분들도 한번 고민해 보고 어떤 것이 단일 책임의 원리를 위반하고 있다고 생각하는지 댓글을 남겨보면 좋겠다. 책에서는 SRP.는 단지 가이드라인일 뿐이지 꼭 이 방법을 따라야 한다는 것은 아니라고 설명하고 있다. 클래스의 기능과 프로젝트에 대한 상식, 그리고 경험을 통해서 디테일한 부분을 스스로 결정해야 한다고 설명하고 있으니 부담 없이 참여해 보시길…

원리 4)
리스코프 치환 원리 LSP(Liskov Substitution Principle)

자식 타입들은 부모 타입들이 사용되는 곳에 대체될 수 있어야 한다는 내용이다. 이는 잘 디자인된 상속에 관한 내용으로 부모 클래스를 상속할 때, 부모 클래스가 사용되는 곳은 아무 문제없이 자식 클래스도 사용할 수 있어야 한다는 것이다. 그렇지 않으면 상속을 잘못 사용하고 있다는 것.

예를 들어 Board라는 클래스는 대부분의 메소드에서 x와 y의 인자를 사용하지만 3DBoard 클래스의 경우는 x,y,z 인자를 사용한다. 이때 3DBoard 클래스가 Board 클래스를 상속하였을 때 3DBoard 클래스에서는 상속된 Board 클래스의 기능이 전혀 필요 없음에도 상속을 하는 경우이다.

이렇게 되었을 때는 상속을 통해서 얻는 것보다 잃는 것이 많아지는데 이는 불필요한 메소드와 구조상 가독성이 떨어지기 때문이다. 불필요한 상속을 피하고 LSP 따를 수 있는 방법으로는 아래와 같은 방법이 있을 수 있다고 설명한다.

1.    상속 보다는 연관을 사용한다
이것은 3DBoard에 Board 인스턴스를 가지고 있으며 Board를 사용하되 zpos 값을 통해서 3DBoard를 표현하는 방법이다.

2.    구성(Composition)을 사용하여 다른 클래스들의 행동을 조합한다.
이 방법은 하나의 인터페이스를 따르는 클래스들의 묶을 배열 형태로 저장하여 필요한 클래스를 동적으로 적용할 수 있는 방법이다. 구성의 경우 구성을 가지고 있는 클래스가 소멸했을 때는 그 클래스에 포함된 구성 요소들도 함께 소멸한다.

3.    집합(Aggregation)을 상용하여 구성에서 구성 요소들이 사라지지 않게 한다.
이 방법은 구성과 비슷하지만 구성 요소들이 외부에서도 사용할 수 있도록 하여 집합을 가지고 있는 인스턴스가 소멸했을 때에도 집합 요소들은 사라지지 않도록 하는 방법이다.

책에서는 LSP위한 방법으로 아래와 같이 정리하고 있다.

1.    위임(Delegation)
클래스의 행동을 변경하고 싶지 않고 그 행동을 스스로 구현하는 것이 그 클래스의 책임이 아닌 경우에는 그 행동을 다른 클래스에 위임(Delegation)한다.

2.    구성(Composition)
구성을 사용하여 하나 또는 여러 개의 클래스, 특히 비슷한 종류의 여러 클래스들로부터 행동을 재사용할 수 있다. 여러분의 객체가 다른 객체를 완전히 소유하고 있는 형태이며, 구성 관계로 연결된 객체는 여러분 객체의 외부에 독립적으로 존재할 수 없다.

3.    집합(Aggregation)
구성 관계의 이점을 바라지만 여러분 객체의 외부에서도 연결된 객체의 행동이 사용되는 경우, 집합을 사용한다.

덧붙여 책에서는 위임과 구성 그리고 집합을 상속보다 선호하면, 대개의 경우 소프트웨어는 더 유연하고, 유지보수성, 확장성, 그리고 재사용성이 좀더 좋아진다고 이야기 하고 있다. 꼭 그런 것은 아니겠지만 LSP를 따르지 않는 상속은 구조를 복잡하게 하고 재사용성이 떨어질 수 있기 때문이라고 할 수 있다. LSP를 따르는 상속의 경우에는 상속을 사용하는 것이 바람직할 것으로 생각된다.


신고
    

설정

트랙백

댓글

Iterator

Programming/Design Patterns 2007.02.21 11:09









1 class DinerMenu{
2         public static var MAX_ITEMS = 6;
3         private var numberOfItems = 0;
4         private var menuItems:Array;
5
6         public function DinerMenu(){
7                 menuItems = new Array();
8
9                 addItem("채식주의자용 BLT", "통밀 위에(식물성) 베이컨, 상추, 토마토를 얹은 메뉴", true, 2.99);
10                 addItem("BLT", "통밀 위에 베이컨, 상추, 토마토를 얹은 메뉴", false, 2.99);
11                 addItem("오늘의 스프", "감자 샐러드를 곁들인 오늘의 스프", false, 3.29);
12                 addItem("핫도그", "사워크라우트, 갖은 양념, 양파, 치즈가 곁들여진 핫도그", false, 3.05);
13
14         }
15
16         public function addItem(name:String, description:String, vegetarian:Boolean, price:Number):Void{
17                 var menuItem:MenuItem = new MenuItem(name, description, vegetarian, price);
18                 if(numberOfItems >= MAX_ITEMS){
19                         trace("죄송합니다. 메뉴가 꽉 찼습니다. 더이상 추가할 수 없습니다.");
20                 }else{
21                         menuItems[numberOfItems] = menuItem;
22                         numberOfItems+=1;
23                 }
24         }
25         /* public function getMenuItems():Array{
26         return menuItems;
27 }*/

28         public function createIterator():Iterator{
29                 return new DinerMenuIterator(menuItems);
30         }
31
32 }

////////////////////////////////////////

 1 class DinerMenuIterator implements Iterator{
2         private var items:Array;
3         private var position:Number;
4
5         public function DinerMenuIterator(items:Array){
6                 this.items = items;
7                 this.position = 0;
8         }
9         public function next():Object{
10                 var menuItem:MenuItem = items[position];
11                 position += 1;
12                 return menuItem;
13         }
14         public function hasNext():Boolean{
15                 if(position>= items.length || items[position] == null){
16                         return false;
17                 }else{
18                         return true;
19                 }
20         }
21 }

///////////////////////////////////////////

 1 interface Iterator{
2         public function hasNext():Boolean;
3         public function next():Object;
4 }

///////////////////////////////////////////

 1 class MenuItem{
2         private var name;
3         private var description:String;
4         private var vegetarian:Boolean;
5         private var price:Number;
6
7         public function MenuItem(name:String, description:String, vegetarian:Boolean, price:Number){
8                 this.name = name;
9                 this.description = description;
10                 this.vegetarian = vegetarian;
11                 this.price = price;
12         }
13         public function getName():String{
14                 return name;
15         }
16         public function getDescription():String{
17                 return description;
18         }
19         public function getPrice():Number{
20                 return price;
21         }
22         public function isVegetarian():Boolean{
23                 return vegetarian;
24         }
25         public function toString():String{
26                 return name+" of MenuItem Object\n";
27         }
28 }

//////////////////////////////////////////

 1 class PancakeHouseMenu{
2         private var menuItems:Array;
3
4         public function PancakeHouseMenu(){
5                 menuItems = new Array();
6                 addItem("K&B 팬케이크 세트", "스크램블드 에그와 포스트가 곁들여진 팬케이크", true, 2.99);
7                 addItem("레귤러 팬케이크 세트", "달걀 후라이와 소시지가 곁들여진 팬케이크", false, 2.99);
8                 addItem("블루베리 팬케이크", "신선한 블루베리와 블루베리 시럽으로 만든 팬케이크", true, 3.49);
9                 addItem("와플", "와플, 취향에 따라 블루베리나 딸기를 얹을 수 있습니다.", true, 3,59);
10         }
11         public function addItem(name:String, description:String, vegetarian:Boolean, price:Number):Void{
12                 var menuItem:MenuItem = new MenuItem(name, description, vegetarian, price);
13                 menuItems.push(menuItem);
14         }
15         /* public function getMenuItems():Array{
16         return menuItems;
17 }*/

18         public function createIterator():Iterator{
19                 return new PancakeIterator(menuItems);
20         }
21 }

/////////////////////////////////////////////

1 class PancakeIterator implements Iterator{
2         private var items:Array;
3         private var position:Number;
4
5         public function PancakeIterator(items:Array){
6                 this.items = items;
7                 this.position = 0;
8         }
9         public function next():Object{
10                 var menuItem:MenuItem = items[position];
11                 position += 1;
12                 return menuItem;
13         }
14         public function hasNext():Boolean{
15                 if(position>= items.length || items[position] == null){
16                         return false;
17                 }else{
18                         return true;
19                 }
20         }
21 }

////////////////////////////////////////////////

 1 class Waitress{
2         private var pancakeHouseMenu:PancakeHouseMenu;
3         private var dinerMenu:DinerMenu;
4
5         public function Waitress(pancakeHouseMenu:PancakeHouseMenu, dinerMenu:DinerMenu){
6                 this.pancakeHouseMenu = pancakeHouseMenu;
7                 this.dinerMenu = dinerMenu;
8         }
9         public function printMenu():Void{
10                 var pancakeIterator:Iterator = pancakeHouseMenu.createIterator();
11                 var dinerIterator:Iterator = dinerMenu.createIterator();
12                 trace("메뉴 ----- \n 아침 메뉴");
13                 printMenuList(pancakeIterator);
14                 trace("\n점심 메뉴");
15                 printMenuList(dinerIterator);
16         }
17         private function printMenuList(iterator:Iterator):Void{
18                 while(iterator.hasNext()){
19                         var menuItem:MenuItem = MenuItem(iterator.next());
20                         trace(menuItem.getName()+", ");
21                         trace(menuItem.getPrice()+"--");
22                         trace(menuItem.getDescription());
23                 }
24
25         }
26 }

////////////////////////////////////////////

 1 class MenuTestDrive{
2         public function MenuTestDrive(){
3                 initialize();
4         }
5         private function initialize():Void{
6                 var pancakeHouseMenu:PancakeHouseMenu = new PancakeHouseMenu();
7                 var dinerMenu:DinerMenu = new DinerMenu();
8                 var waitress:Waitress = new Waitress(pancakeHouseMenu, dinerMenu);
9                 waitress.printMenu();
10         }
11 }
신고
    

설정

트랙백

댓글

TemplateMethod

Programming/Design Patterns 2007.02.21 11:09
 1 class CaffeineBeverage{
2         public function prepareRecipe():Void{
3                 boilWater();
4                 brew();
5                 pourInCup();
6                 if(hook()){
7                         addCondiments();
8                 }
9         }
10         public function brew():Void{
11
12         }
13         public function addCondiments():Void{
14
15         }
16         public function boilWater():Void{
17                 trace("물 끓이는 중");
18         }
19         public function pourInCup():Void{
20                 trace("컵에 따르는 중");
21         }
22         public function hook():Boolean{
23                 return true;
24         }
25 }

/////////////////////////////////////////////

 1 class Coffee extends CaffeineBeverage{
2         public function brew():Void{
3                 trace("필터로 커피를 우려내는 중");
4         }
5         public function addCondiments():Void{
6                 trace("설탕과 커피를 추가하는 중");
7         }
8         public function hook():Boolean{
9                 return false;
10         }
11 }

//////////////////////////////////////////////

 1 class Tea extends CaffeineBeverage{
2         public function brew():Void{
3                 trace("차를 우려내는 중");
4         }
5         public function addCondiments():Void{
6                 trace("레몬을 추가하는 중");
7         }
8 }

//////////////////////////////////////////////

 1 class TemplateTest{
2         public function TemplateTest(){
3                 init();
4         }
5         private function init():Void{
6                 var tea:CaffeineBeverage = new Tea();
7                 var coffee:CaffeineBeverage = new Coffee();
8
9                 trace("Tea Test..............");
10                 tea.prepareRecipe();
11
12                 trace("Coffee Test...........");
13                 coffee.prepareRecipe();
14         }
15 }
신고
    

설정

트랙백

댓글

Adapter

Programming/Design Patterns 2007.02.21 11:08
 1 interface Duck{
2         public function quack():Void;
3         public function fly():Void;
4 }

////////////////////////////////////

 1 class MallardDuck implements Duck{
2         public function quack():Void{
3                 trace("Quack");
4         }
5         public function fly():Void{
6                 trace("I'm flying");
7         }
8 }

/////////////////////////////////////

 1 interface Turkey{
2         public function gobble():Void;
3         public function fly():Void;
4 }

/////////////////////////////////////

class TurkeyAdapter implements Duck{
        private var turkey:Turkey;
        public function TurkeyAdapter(turkey:Turkey){
                this.turkey = turkey;
        }
        public function quack():Void{
                turkey.gobble();
        }
        public function fly():Void{
                for(var i=0;i<5;i++){
                        turkey.fly();
                }
        }
}


//////////////////////////////////////

 1 class WildTurkey implements Turkey{
2         public function gobble():Void{ 3 trace("Gobble gobble");
4         }
5         public function fly():Void{
6                 trace("I'm flying a short distance");
7         }
8 }

//////////////////////////////////////

 1 class DuckTestDrive{
2         public function DuckTestDrive(){
3                 initialize();
4         }
5         public function initialize():Void{
6                 var duck:MallardDuck = new MallardDuck();
7
8                 var turkey:WildTurkey = new WildTurkey();
9                 var turkeyAdapter:Duck = new TurkeyAdapter(turkey);
10
11                 trace("The Turkey says...");
12                 turkey.gobble();
13                 turkey.fly();
14
15                 trace("The Duck says...");
16                 testDuck(duck);
17
18                 trace("The TurkeyAdapter says...");
19                 testDuck(turkeyAdapter);
20         }
21         private function testDuck(duck:Duck):Void{
22                 duck.quack();
23                 duck.fly();
24         }
25
26 }
신고
    

설정

트랙백

댓글

Command

Programming/Design Patterns 2007.02.21 11:08
 1 interface Command{
2         public function execute();
3 }

///////////////////////////////

 1 class Light{
2         private var name:String;
3         public function Light(name:String){
4                 this.name = name;
5         }
6         public function lightOn():Void{
7                 trace(name+" : 불을 켜다");
8         }
9         public function lightOff():Void{
10                 trace(name+" : 불을 끄다");
11         }
12 }

/////////////////////////////////

 1 class LightOffCommand implements Command{
2         private var light:Light;
3
4         public function LightOffCommand(light:Light){
5                 this.light = light;
6         }
7         public function execute(){
8                 light.lightOff();
9         }
10 }

////////////////////////////////////

 1 class LightOnCommand implements Command{
2         private var light:Light;
3
4         public function LightOnCommand(light:Light){
5                 this.light = light;
6         }
7         public function execute(){
8                 light.lightOn();
9         }
10 }

/////////////////////////////////////

 1 class RemoteControl{
2         private var onCommands:Array;
3         private var offCommands:Array;
4
5         public function RemoteControl(){
6                 onCommands = new Array();
7                 offCommands = new Array();
8         }
9         public function setCommand(slot:Number, onCommand:LightOnCommand, offCommand:LightOffCommand):Void{
10                 onCommands[slot] = onCommand;
11                 offCommands[slot] = offCommand;
12         }
13         public function onButtonWasPressed(slot:Number):Void{
14                 onCommands[slot].execute();
15         }
16         public function offButtonWasPressed(slot:Number):Void{
17                 offCommands[slot].execute();
18         }
19 }

//////////////////////////////////////

 1 class RemoteControlTest
2 {
3         public function RemoteControlTest ()
4         {
5                 init ();
6         }
7         public function init () : Void
8         {
9                 var remote : RemoteControl = new RemoteControl ();
10                 var light : Light = new Light ("스텐드");
11                 var lightOn : LightOnCommand = new LightOnCommand (light);
12                 var lightOff : LightOffCommand = new LightOffCommand (light);
13                 remote.setCommand (0, lightOn, lightOff);
14                 remote.onButtonWasPressed (0);
15                 remote.offButtonWasPressed (0);
16         }
17 }

신고
    

설정

트랙백

댓글

Singleton

Programming/Design Patterns 2007.02.21 11:08
 1 class Singleton{
2         private static var uniqueInstance;
3
4         private function Singleton(){
5
6         }
7         public static function getInstance():Singleton{
8                 if(uniqueInstance == null){
9                         uniqueInstance = new Singleton();
10                 }
11                 return uniqueInstance;
12         }
13         public function getName(){
14                 trace("Singleton pattern");
15         }
16 }
신고
    

설정

트랙백

댓글

Factory

Programming/Design Patterns 2007.02.21 11:07
 1 class SimplePizzaFactory{
2         public function createPizza(type:String):Pizza{
3                 var pizza:Pizza = null;
4                 if(type == "cheese"){
5                         pizza = new CheesePizza();
6                 }else if(type == "pepperoni"){
7                         pizza = new PepperoniPizza();
8                 }else if(type == "clam"){
9                         pizza = new ClamPizza();
10                 }else if(type == "veggie"){
11                         pizza = new VeggiePizza();
12                 }
13                 return pizza;
14         }
15 }

////////////////////////////////////////

 1 class CheesePizza extends Pizza{
2         public function CheesePizza(){
3                 pizza_name = "CheesePizza";
4                 dough = "얇게";
5                 sauce = "짜게";
6         }
7
8         private function bake(){
9                 trace("Bake for 25 minutes at 350");
10         }
11         private function cut(){
12                 trace("Cutting the pizza into diagonal slices");
13         }
14         private function box(){
15                 trace("Place pizza in official PizzaStore box");
16         }
17         public function getName():String{
18                 return pizza_name;
19         }
20 }

/////////////////////////////////

 1 class VeggiePizza extends Pizza{
2         public function VeggiePizza(){
3                 pizza_name = "VeggiePizza";
4                 dough = "굵게";
5                 sauce = "달게";
6         }
7
8         private function bake(){
9                 trace("Bake for 25 minutes at 350");
10         }
11         private function cut(){
12                 trace("Cutting the pizza into diagonal slices");
13         }
14         private function box(){
15                 trace("Place pizza in official PizzaStore box");
16         }
17         public function getName():String{
18                 return pizza_name;
19         }
20 }

/////////////////////////////////////////////

 1 class ClamPizza extends Pizza{
2         public function ClamPizza(){
3                 pizza_name = "ClamPizza";
4                 dough = "굵게";
5                 sauce = "달게";
6         }
7
8         private function bake(){
9                 trace("Bake for 25 minutes at 350");
10         }
11         private function cut(){
12                 trace("Cutting the pizza into diagonal slices");
13         }
14         private function box(){
15                 trace("Place pizza in official PizzaStore box");
16         }
17         public function getName():String{
18                 return pizza_name;
19         }
20 }

//////////////////////////////////////

 1 class PepperoniPizza extends Pizza{
2         public function PepperoniPizza(){
3                 pizza_name = "PepperoniPizza";
4                 dough = "굵게";
5                 sauce = "달게";
6         }
7
8         private function bake(){
9                 trace("Bake for 25 minutes at 350");
10         }
11         private function cut(){
12                 trace("Cutting the pizza into diagonal slices");
13         }
14         private function box(){
15                 trace("Place pizza in official PizzaStore box");
16         }
17         public function getName():String{
18                 return pizza_name;
19         }
20 }

/////////////////////////////////////////

 1 class Pizza{
2         private var pizza_name:String;
3         private var dough:String;
4         private var sauce:String;
5         private var ary:Array = new Array();
6
7         public function prepare(){
8                 trace("피자이름 : "+pizza_name);
9
10         }
11         public function bake(){
12                 trace("Bake for 25 minutes at 350");
13         }
14         public function cut(){
15                 trace("Cutting the pizza into diagonal slices");
16         }
17         public function box(){
18                 trace("Place pizza in official PizzaStore box");
19         }
20         public function getName():String{
21                 return pizza_name;
22         }
23
24 }

///////////////////////////////////////

 1 class PizzaStore{
2         private var factory:SimplePizzaFactory;
3         public function PizzaStore(factory:SimplePizzaFactory){
4                 this.factory = factory;
5         }
6         public function orderPizza(type:String):Pizza{
7                 var pizza:Pizza; 8 pizza = factory.createPizza(type);
9                 pizza.prepare();
10                 // pizza.bake();
11                 // pizza.cut();
12                 // pizza.box();
13                 return pizza;
14         }
15 }

////////////////////////////////////////
var myPizzaStore:PizzaStore = new PizzaStore(new SimplePizzaFactory());
myPizzaStore.orderPizza("cheese");
myPizzaStore.orderPizza("pepperoni");
myPizzaStore.orderPizza("clam");
myPizzaStore.orderPizza("veggie");


신고
    

설정

트랙백

댓글

Decorator

Programming/Design Patterns 2007.02.21 11:07
 1 class Beverage{
2         private var descriptions:String = "제목없음";
3         public function getDescription():String{
4                 return descriptions;
5         }
6         public function cost():Number{
7                 return 0;
8         }
9 }

////////////////////////////////////

 1 class CondimentDecorator extends Beverage{
2         public function getDepscription(){
3
4         }
5 }

////////////////////////////////////

 1 class DarkRoast extends Beverage{
2         public function DarkRoast(){
3                 descriptions = "다트로스트 커피";
4         }
5         public function cost():Number{
6                 return 2.89;
7         }
8 }

/////////////////////////////////////

 1 class Espresso extends Beverage{
2         public function Espresso(){
3                 descriptions = "에스프레소";
4         }
5         public function cost():Number{
6                 return 1.99;
7         }
8 }

//////////////////////////////////////

 1 class HouseBlend extends Beverage{
2         public function HouseBlend(){
3                 descriptions = "하우스 브렌드 커피";
4         }
5         public function cost():Number{
6                 return .89;
7         }
8 }

//////////////////////////////////////

 1 class Mocha extends CondimentDecorator{
2         private var beverage:Beverage;
3         public function Mocha(beverage:Beverage){
4                 this.beverage = beverage;
5         }
6         public function getDescription():String{
7                 return beverage.getDescription()+", 모카";
8         }
9         public function cost():Number{
10                 return .20+beverage.cost();
11         }
12 }

///////////////////////////////////////

 1 class Whip extends Beverage{
2         private var beverage:Beverage;
3         public function Whip(beverage:Beverage){
4                 this.beverage = beverage; 5 } 6 public function getDescription():String{
7                 return beverage.getDescription()+", 휘핑";
8         }
9         public function cost():Number{
10                 return .20+beverage.cost();
11         }
12 }

///////////////////////////////////////

 1 class Main{
2         public function Main(){
3                 init();
4         }
5         private function init(){
6                 var beverage:Beverage = new Espresso();
7                 trace(beverage.getDescription()+" $"+beverage.cost());
8
9                 var beverage2:Beverage = new DarkRoast();
10                 beverage2 = new Mocha(beverage2);
11                 beverage2 = new Mocha(beverage2);
12                 beverage2 = new Whip(beverage2);
13                 trace(beverage2.getDescription()+" $"+beverage2.cost());
14
15                 var beverage3:Beverage = new HouseBlend();
16                 beverage3 = new Mocha(beverage3);
17                 beverage3 = new Whip(beverage3);
18                 trace(beverage3.getDescription()+" $"+beverage3.cost());
19
20         }
21 }
신고
    

설정

트랙백

댓글

Observer

Programming/Design Patterns 2007.02.21 11:06
 1 class CurrentConditionsDisplay implements Observer, DisplayElement{
2         private var temperature:Number;
3         private var humidity:Number;
4         private var pressure:Number;
5         private var weatherData:Subject;
6
7         public function CurrentConditionsDisplay(weatherData:Subject){
8                 this.weatherData = weatherData;
9                 weatherData.registerObserver(this);
10         }
11         public function update(temperature:Number, humidity:Number, pressure:Number):Void{
12                 this.temperature = temperature;
13                 this.humidity = humidity;
14                 this.pressure = pressure;
15                 display();
16         }
17         public function display():Void{
18                 trace("Temperature: "+temperature);
19                 trace("Humidity: "+humidity);
20                 trace("Pressure: "+pressure);
21                 trace("----------------------");
22         }
23 }

////////////////////////////////////////////////////////////////

 1 interface DisplayElement{
2         public function display():Void;
3 }

////////////////////////////////////////////////////////////////

 1 interface Observer{
2         public function update(temp:Number, humidity:Number, pressure:Number):Void;
3 }

///////////////////////////////////////////////////////////////
 1 interface Subject{
2         public function registerObserver(o:Observer):Void;
3         public function removeObserver(o:Observer):Void;
4         public function notifyObserver():Void;
5 }

///////////////////////////////////////////////////////////////

 1 class WeatherData implements Subject{
2         private var observers:Array;
3         private var temperature:Number;
4         private var humidity:Number;
5         private var pressure:Number;
6
7         public function WeatherData(){
8                 observers = new Array();
9         }
10         public function registerObserver(o:Observer):Void{
11                 observers.push(o);
12         }
13         public function removeObserver(o:Observer):Void{
14                 var lastIndex:Number = observers.length;
15                 for(var i=0;i<lastIndex;i++){
16                         if(observers[i] == o){
17                                 observers.splice(i,1);
18                         }
19                 }
20         }
21         public function notifyObserver():Void{
22                 var lastIndex:Number = observers.length;
23                 for(var i=0;i< lastIndex;i++){
24                         var observer:Observer = Observer(observers[i]);
25                         observer.update(temperature, humidity, pressure);
26                 }
27         }
28         public function measurementsChanged():Void{
29                 notifyObserver();
30         }
31         public function setMeasurements(temperature:Number, humidity:Number, pressure:Number):Void{
32                 this.temperature = temperature;
33                 this.humidity = humidity;
34                 this.pressure = pressure;
35                 measurementsChanged();
36         }
37 }

//////////////////////////////////////////////////////////////

 1 class WeatherStation{
2         public function WeatherStation(){
3                 var weatherData:WeatherData = new WeatherData();
4                 var weatherData2:WeatherData = new WeatherData();
5                 var currentDisplay:CurrentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
6                 var currentDisplay:CurrentConditionsDisplay = new CurrentConditionsDisplay(weatherData2);
7                 weatherData.setMeasurements(80,30,23);
8                 weatherData2.setMeasurements(11,22,33);
9                 weatherData.setMeasurements(22,30,23);
10
11         }
12 }

///////////////////////////////////////////////////////////////////


신고
    

설정

트랙백

댓글

StrategyPattern

Programming/Design Patterns 2007.02.21 11:06
class Duck{
        public var flyBehavior:FlyBehavior;
        public var quackBehavior:QuackBehavior;

        public function Duck(){

        }
        public function swim():Void{

        }
        public function display():Void{

        }
        public function performQuack():Void{
                quackBehavior.quack();
        }
        public function performFly():Void{
                flyBehavior.fly();
        }
        public function setFlyBehavior(fb:FlyBehavior):Void{
                flyBehavior = fb;
        }
        public function setQuackBehavior(qb:QuackBehavior):Void{
                quackBehavior = qb;
        }
}

////////////////////////////////////////////////

interface FlyBehavior{
        public function fly():Void;
}
////////////////////////////////////////////////
class FlyNoWay implements FlyBehavior{
        public function fly():Void{
                trace("저 안 날아요");
        }
}
////////////////////////////////////////////////
class FlyWithWings implements FlyBehavior{
        public function fly():Void{
                trace("저 날아요");
        }
}
////////////////////////////////////////////////
class ModelDuck extends Duck{
        public function ModelDuck(){
                flyBehavior = new FlyNoWay();
                quackBehavior = new MuteQuack();
        }
        private function display():Void{
                trace("가짜 오리입니다");
        }
}
////////////////////////////////////////////////
class MuteQuack implements QuackBehavior{
        public function quack():Void{
                trace("나 벙어리");
        }
}
///////////////////////////////////////////////
class Quack implements QuackBehavior{
        public function quack():Void{
                trace("꽥꽥");
        }
}
/////////////////////////////////////////////////
interface QuackBehavior{
        public function quack():Void;
}
/////////////////////////////////////////////////
class Squack implements QuackBehavior{
        public function quack():Void{
                trace("삑삑");
        }
}
/////////////////////////////////////////////////
class Main{
        private var myDuck:Duck;
        public function Main(){
                myDuck = new ModelDuck();
                init();
        }
        private function init():Void{
                myDuck.display();
                myDuck.performFly();
                myDuck.performQuack();
                myDuck.setFlyBehavior(new FlyWithWings());
                myDuck.performFly();

        }
}
/////////////////////////////////////////////////
신고
    

설정

트랙백

댓글

Iterator Design Pattern

Programming/Design Patterns 2007.02.21 10:54
// Iterator interface //

interface Iterator{
public function hasNext():Boolean;
public function next():Object;
}

// Aggregate interface //

interface Aggregate{
public function iterator():Iterator;
}

// Book class //

class Book{
private var name:String = "";
public function Book(name:String){
this.name = name;
}
public function getName():String{
return name;
}
}


// BookShelfIterator class //

class BookShelfIterator implements Iterator{
private var bookShelf:BookShelf;
private var index:Number;
private var book:Book;
public function BookShelfIterator(bookShelf:BookShelf){
this.bookShelf = bookShelf;
this.index = 0;
}
public function hasNext():Boolean{
if(this.index < bookShelf.getLength()){
return true;
}else{
return false;
}
}
public function next():Object{
this.book = bookShelf.getBookAt(this.index);
this.index++;
return this.book;
}
}



// BookShelf class//



class BookShelf implements Aggregate{
private var books:Array;
private var last:Number = 0;
public function BookShelf(){
this.books = new Array();
}
public function getBookAt(index:Number):Book{
return books[index];
}
public function appendBook(book:Book):Void{
this.books[last] = book;
last++;
}
public function getLength():Number{
return last;
}
public function iterator():Iterator{
return new BookShelfIterator(this);
}
}



// Main class //

class Main{
private var bookShelf:BookShelf;
private var it:Iterator;
private var book:Book;
public function Main(){
init();
}
public function init(){
this.bookShelf = new BookShelf();
this.bookShelf.appendBook(new Book("Around the World in 80 Days"));
this.bookShelf.appendBook(new Book("Bible"));
this.bookShelf.appendBook(new Book("Cinderella"));
this.bookShelf.appendBook(new Book("Daddy-Long-Legs"));
this.it = bookShelf.iterator();
while(it.hasNext()){
this.book = Book(it.next());
trace(""+this.book.getName());
}
}
}
신고
    

설정

트랙백

댓글