웹써핑중에 라면 만들기 강좌를 활용한 좋은 예가 있어 소개해드릴까 합니다.

원래 라면 만들기 강좌 다음 버전은 어렵지 않으면서도 활용하기 좋은 다른 패턴을 쉽게 풀어보려고 했는데

한 놈만 제대로 이해한다면 다른 패턴들을 공부할때 쉽게 수긍 할 수 있는 부분이 많다고 봤습니다.

 

어째든.. 그냥 긁어다 붙이면 너무 성의가 없으니 기사를 적절히 끊어서 설명하겠습니다.

 

Continuing with this idea of showing alternatives using the same example, I thought it might be interesting to show the Decorator Pattern which can be used when the Policy Injection Application Block and PostSharp may be overkill for your application.

In the two examples mentioned above I created a Stopwatch Attribute that timed the ILogger.Write Method used in our console application:

 

public interface ILogger

{

    void Write(string message);

}

 

public class ConsoleLogger : ILogger

{

    public void Write(string message)

    {

        Console.WriteLine();

        Console.WriteLine("*** In Logger ***");

        Console.WriteLine(string.Format

            ("message : {0}", message));

    }

}

 

참고로 이 기사를 쓴 분은 MS의 log 관련 application block을 쓰는 모양인데

저는 log4net을 씁니다. 그래서 관련 코드에대해서는 설명이 부족할 수 있습니다. 

 

음.. 어째든 위 소스를 보니 ConsoleLoggerILogger라는 추상화된 컴퍼넌트를 구현하고 있군요.

아직 데코레이터 클래스는 나오지 않았습니다. 아마 이 놈이 라면이 될 모양입니다.

ConsoleLogger에 Write()라는 기능을 나중에 동적으로 추가시키려고 하는것이겠죠.

 

그런데 라면 만들기때는 abstract class를 사용했습니다. 왜냐하면 공통된 구현이 많아서

최상위 클래스에서 일부 구현을 해주는게 편했기 때문이죠. 어떤 객체를 추상화의 수준을

interface냐 abstract class냐는 상황에 따라 다릅니다. 거의 대부분이 Interface를 쓰지만요.

 

Creating these attributes is pretty simple for use in the Policy Injection Application Block and PostSharp. However, we can avoid the use of these 3rd party libraries by creating a StopwatchLoggerDecorator Class that will achieve the same results:

 

public class StopwatchLoggerDecorator : ILogger

{

    private readonly ILogger _inner;

 

    public StopwatchLoggerDecorator(ILogger inner)

    {

        _inner = inner;

    }

 

    public void Write(string message)

    {

        Stopwatch sw = new Stopwatch();

        sw.Start();

 

        _inner.Write(message);

 

        sw.Stop();

 

        Console.WriteLine();

        Console.WriteLine(string.Format("Time Elapsed: {0} ms", sw.ElapsedMilliseconds));

    }

}

 

아.. 바로 데코레이터가 만들어졌군요. 라면 만들기때와는 달리 데코레이터의 추상화는 없는것 같습니다.

이 경우를 단일 데코레이터라고 합니다. 그런데 라면 만들기때는 재료(데코레이터)가 다양했습니다.

다음과 같이 아무리 감싸도 결국 라면이되는 표현  new 재료2(new 재료1(new 라면()))..

이렇게 되기위해서 데코레이터는 자기가 감싸야 될 클래스의 추상화 클래스를 구현할 필요가 있었습니다.

c# 코드상에서 재료 as 라면과 같은 표현이 가능해야 된다고도 했었죠.

 

라면 만들기에서 재료라는 데코레이터는 다양했었고 각 재료들마다의 개별적인 메서드들이

있을수 있었기 때문에 재료라는 데코레이터의 추상화를 만들어주는것이 필요했습니다.

그리고 각 재료들은 그 추상화된 객체를 구현하도록 했었지요.  

이것을 다중 데코레이터라고 합니다.

 

소스로 돌아가서.. 역시 이번 데코레이터도 ConsoleLogger가 구현한 ILogger를 구현했군요.

이건 공식에 가깝습니다. 이 패턴에서는 자기가 감싸게 될 놈의 추상화 객체를 구현해야만 합니다.

 

이 데코레이터는 Write()가 수행되는 시간을 계산하는 기능이 추가되어있습니다.

핵심은 역시 생성자에서 ILogger라는 자기가 감싸게 될 추상화 객체를 인자로 받는 것이죠.

이런식으로 내부적으로 다른 객체를 생성하지 않고 관계를 맺는것이 모든 패턴들의 특징입니다.

(이런 관계를 is-a 관계라고 하고 반대로 객체안에서 객체를 생성하게 되는것을 has-a관계라고 합니다.)

 

우리는 Write() 기능이 데코레이터 되었다는걸 명확히 알 수 있습니다.

ILogger를 구현한 클래스의 Write()를 재사용하면서 그 기능에 스톱와치 클래스의 기능까지 추가했습니다.

 

그런데 Stopwatch라는 클래스는 우리가 소스를 건들일수 없는 상용 컴퍼넌트였다면..

생각해보세요. Log에 그 기능을 추가하기 위해선 applicatoin block의 소스를 뜯어 고치던가 했어야 했던지

합치지 못하고 분리해서 호출했어야 할지도 모르죠. 데코레이터 패턴을 안다면 그런 생각자체를 못하겠지만..

 

어째든 이름도 잘 지었네요. 이 데코레이터의 이름은 그래서 StopwatchLoggerDecorator 이군요.

이런식으로 네이밍 하는것은 권장되는 사항입니다. 코드만 봐도 그 의도가 드러나기 때문에

따로 주석을 쓸 이유도 없습니다.

 

아래에 이 데코레이터를 적용한 예가 있습니다.

 

The Decorator Class implements the same ILogger Interface and takes the "real" ILogger in its constructor, ConsoleLogger. Inevitably it passes the Write Call onto the real logger, but before doing so starts a Stopwatch. After the call to ConsoleLogger is finished ( _inner.Write ), it stops the Stopwatch and displays the elapsed time in the console.

In keeping with the examples mentioned above, one can register the ILogger in your IoC Container / Dependency Injection Tool of choice. Here is an example using Unity:

 

IUnityContainer container = new UnityContainer();

 

 

// Register Logger

ILogger consoleLogger = new ConsoleLogger();

 

ILogger logger = new StopwatchLoggerDecorator(consoleLogger);

 

container.RegisterInstance<ILogger>(logger,

    new ContainerControlledLifetimeManager());

 

 

// Use Logger

var registeredLogger = container.Resolve<ILogger>();

 

registeredLogger.Write("Hello!");

 

Console.ReadLine();

 

The results are as follows:

 

Decorator Pattern

 

 

위 소스에서 데코레이터를 적용한 부분은 아래와 같습니다.

 

ILogger consoleLogger = new ConsoleLogger();

ILogger logger = new StopwatchLoggerDecorator(consoleLogger);

 

이 부분만 보세요. 라면 만들기때와 마찬가지로 라면을 재료로 요리했군요.

간단히 logger.Write(); 써주면 결과화면처럼 나오게 됩니다.

(Write()의 호출이 원문과 다르긴 하지만.. 실제로 저렇게 써도 되는거니 넘어가죠. -_-)

 

이 기사를 쓴 목적이 ConsoleLogger를 변경하지 않고도 새로운 기능을 추가하는것이였는데 성공적입니다.

그런데 우리의 고객이 이왕 출력되는거 html 출력으로도 보고 싶어합니다.

여러분은 어쩌시겠습니까? Write() 메서드를 오버로딩하시겠다고요? 왜이러시나요..

(한번 해보세요.. 되는지.. -_-)

Write() 메서드에 인자를 받게 만들어 내부에서 if를 써서 분기를 하시겠다고요? 역시 안됩니다.. -_-

HTMLLoggerDecorator를 만드셔야죠. 그리곤 사용은 아래와 같이 쓸수있어야 합니다.

 

new HTMLLoggerDecorator(consoleLogger);

또는 new HTMLLoggerDecorator(new StopwatchLoggerDecorator(consoleLogger))

 

HTMLLoggerDecorator는 어떻게 구현해야 할까요? (html 태그를 어렵게 적용시키려 하지 마세요-_-)

 

참고로.. new StopwatchLoggerDecorator(new HTMLLoggerDecorator(consoleLogger))와 같이 쓰게되면

이상한 출력결과가 나올수 있습니다. 감싸는 순서가 HTMLLoggerDecorator 만든 의도와는 달리 사용이

되었기 때문인데요. 이런 문제들은 팩토리나 빌더같은 다른 생성패턴들과 결합해서 써야 될 필요성이

있습니다. 팩토리나 빌더는 다음에 좋은 예가 떠오르면 글을 올려보도록 하겠습니다.

 

이 글이 패턴을 이해하는데 조금이나마 도움이 되었기를 바랍니다.

 

전체 기사 링크

http://codebetter.com/blogs/david.hayden/archive/2008/09/30/decorator-pattern.aspx

 


출처 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1635&page=1

혹시 일본식 라면집에 가보셨나요? 저는 여자친구와 갔다가 곰탕같은 라면을 시켜먹었는데(으웩...) 그게 8년전 애기입니다.

개인적으로 라면은 우리나라, 삼양라면을 좋아합니다. 가끔 너구리도 먹어주시면 흐뭇해지고요. 그리고 일요일엔 짜파게티죠~

오늘 이 자리를 빌어 저와같이 라면을 좋아하시는(돈이 없어 라면을 드시던간에-_-) 우리나라 프로그래머님들을 위해

저만의 비법을 알려드리겠습니다. 물론 어떤 댓가를 바라진 않습니다. 다만 응용한 결과를 저에게도 알려주시면 고마울뿐이죠.

 

아래는 제가 만든 첫번째 라면입니다.

 

 

소스를 보니 텅~ 빈 생성자 하나에 설명이라는 속성 그리고 가격이라는 메소드가 있군요.

설명이 무안 할 정도로 단순하지만.. 얼마나 복잡하게 될 수 있는지 보기로 하죠.

 

이제 이런 형태로 된장라면, 간장라면, 곰탕라면, 짜장라면, 김치라면, 카레라면, 조개라면, 사노라면, 짬뽕라면,

된장조개라면, 고추조개라면, 짜장된장라면, 고추짜장라면, 고추된장카레조개짬뽕라면.. 등등등..

 

지면상-_- 나머지 라면들을 나열하는것은 생략하고 이 정도만 만들어 보죠.

대충 복사해서 이름하고 가격만 바꿔주면 될듯 보입니다.

자.. 이제 평소에 잘하시는 ctrl+c, ctrl+v 신공을 발휘할때가 왔네요.

 

그런데 가만 들여다보면 단순하진 않습니다. 그렇게 쉽게 해결 될 문제가 아닌거죠.

그 이유로 고추조개라면의 경우로 예를 들면 가격()을 구현해야 하는데

아래 소스에서 보다시피 참조되는 라면들의 가격을 반영해야 합니다.

 

 

만약 고추/된장/카레/조개/간장/양파/해삼/멍게/오징어/짬뽕라면 이라면... 그외

카레/조개/간장/양파/해삼/멍게라면,  해삼/멍게/오징어/짬뽕라면 등등 다양한 조합들이 있으므로

가격이란 메소드 작성이 쉽지 않습니다.

 

더구나 이 글을 보신 분들의 요청에 의해 라면의 종류는 더 늘고 복잡해질지 모릅니다.

 

... 왜 문제가 되는지 생략 ...

 

여기에 이 문제를 해결 할 비법이 있습니다.

 

우선 라면에대해 다시 생각해 볼 필요가 있습니다.

다 알다시피 라면은 어떤 재료가 들어가냐에 따라서 종류가 달라지고 어떤 라면이 될지가 결정됩니다.

그리고 재료는 하나이상 복합적으로 들어갈 수 있고(안들어갈수도 있군요) 이에따라 라면의 가격도 달라집니다.

이 둘의 관계는 달리말하면 라면은 재료에 함수적 종속성을 가지게 됩니다. 재료가 라면을 결정짓게 되는것이죠.

 

따라서 우리는 라면과 재료의 관계를 재정립하고 이를 코드로 분리해서 관리 할 필요성이 있습니다.

라면은 재료에의해 설명도 가격도 달라지므로 둘을 합치거나 또는 서로가 포함관계에 있으면 코드의 중복과

복잡도가 증가하고 재료비나 또는 가격을 계산하는 로직이 변경될 경우 수정에 많은 힘이 드는 상황이 발생합니다.

 

해결책은 아래와 같이 라면과 재료라는 추상화된 객체를 만드는것으로부터 시작합니다.

여기서 핵심은 재료로 라면에 어떠한 행위를 한 뒤에라도 라면으로써 사용이 가능해야 합니다. (현실도 그렇죠)

기본라면에 어떤 재료를 넣어 만들어진 라면도 라면이고, 그렇게 만들어진 라면에 다시 재료를 추가해도 라면이라는 말이죠.

따라서 재료 클래스는 추상화된 라면 클래스를 구현또는 상속받아야 합니다. 재료 as 라면이 성립되어야 하니까요.

또 재료만의 속성과 메소드를 가질수 있으니 이것을 객체로 만드는데는 이의가 없습니다.

 

(인터페이스로 구현해도 됩니다. 하지만 여기선 추상클래스로..)

 

 

이걸 바탕으로 아래와 같이 고추라는 재료를 만들수 있습니다.

재료의 생성자에 가공(요리) 할 대상인 라면의 레퍼런스를 넘겨주는것에 주목 할 필요가 있습니다.

 

 

설명 속성은 넘겨받은 라면에 재료명을 더해주는것만으로 깔끔하게 완성된 코드입니다.

마찬가지로 가격 메소드 또한 가공(요리) 할 라면가격에 재료(고추)의 가격을 더해주면 됩니다.

이렇게 기본라면에 고추를 넣은 후에도 라면으로봐야죠. 가공(요리)된 라면에 다시 고추를 넣어도 라면입니다.

그럼 고추고추라면이 되겠군요. -_- 

 

끝에가면 예제가 있으나 우선 사용예를 보겠습니다.

 

라면 고추라면 = new 고추( new 라면인스턴스() );

라면 고추고추라면 = new 고추( new 고추( new 라면인스턴스() ) );

 

고추고추라면.가격() 메서드를 호출하면 ( 고추재료가격 + ( 고추재료가격 + 라면가격) ) 과 같은 계산이 이뤄지게 됩니다.

 

그럼 고추와 같은 방법으로 조개라는 재료도 만들어보죠.

 

 

자.. 이제 재료도 대충 만들었으니 재료들을 넣을 라면을 만들어 볼 차례입니다.

아직 실체화된 라면이 없었습니다. 여기선 그냥 삼양라면을 만들어 보겠습니다.

 

 

이제서야 라면을 요리 할 시간이 되었군요.

재료도 구비되었으니 이제 라면을 재료로 새롭게 재탄생시킬수 있습니다.

 

 

라면을 고추로 감싸서 고추라면을,

라면을 조개로 감싸고 다시 고추로 감싸니까

고추조개삼양라면이 만들어집니다.

 

고추조개삼양라면을 양파라는 재료 클래스로 감싸주면?

양파고추조개삼양라면이 되겠죠.

 

 

실행 결과화면

 

 

어떤가요?

 

라면 클래스(여기서는 추상화된 라면 클래스를 구현한 삼양라면을 말합니다) 자체는 손대지 않았습니다.

단지 재료로 감싸준것 뿐이죠. 또 단가의 계산도 간결하게 해결 되었습니다.

 

그런데 결과화면을 보니 고추/조개/삼양라면 순이 아니라 읽고 부르기엔 웬지 이상합니다.

이 문제를 수정하기 위해 기존 클래스들을 수정해야 할까요?

우리는 방금 원본 클래스에 손도 대지않고 원하는 기능을 구현하는 방법을 배웠습니다.

따라서 이번에도 그런 방식으로 해보는게 좋겠군요.

 

아래와 같이 DescriptionDeco라는 클래스를 만들어봤습니다.

역시 여기서의 핵심도 라면이라는 추상화 클래스를 상속받고 생성자에선 가공해야 할 라면 클래스를 넘겨받는것이죠.

이렇게 하면 기존 코드의 변경이 일어나지 않습니다.

 

(단지 설명을 출력하는 기능에대한 확장이므로 가격은 변동이 없습니다. 공짜란 말이죠.)

 

적용 예입니다.

 

 

결과화면

 

 

 

* 실행가능한 전체소스를 첨부하였으니 참고하세요.

 

 

마무리

 

별로 쓴 내용도 없는데 이걸 작성하는데 2시간이나 걸렸네요. 원래는 대충 설명하고 비주얼한 예제를 쓸려고 했는데

이 속도로는 어렵겠군요. -_-  이외에도 좀 더 많은 할 애기가 있지만 여기서 끊는게 좋겠습니다.

아시는 분들은 이미 아셨을수도 있는데 위 내용은 Head First Design Patterns 책을 약간 패러디한것으로

데코레이션 패턴에 해당하는 내용입니다. 미숙한 글이나마 도움이 되었으면 합니다.

 

 

용어정리

 

추상화 클래스인 라면을 Component,

이 클래스를 상속받아 구현된 삼양라면을 ConcreateComponent라고 합니다.

Decorator는 추상화된 재료 클래스 입니다.

 

일반적으로 Component는 어떤 행위를 정의한 인터페이스와 같이 추상화된 객체일 수 있습니다.

이걸 상속받아 구현된 ConcreateComponent는 Decorator가 감싸게 될 클래스이고요.

 

Decorator Pattern의 경우 객체의 변형없이 상속또는 구현을 통해 객체의 기능을

유연하게 확장 할 수 있는 방법으로 자주 사용됩니다.

실무에서 부담없이 적용해 볼 만한 몇개 안되는 패턴중에 하나입니다.


출처 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1627&page=1


개 요

 

이번에는 닷넷의 특징이라고 할 수 있는 Boxing, Unboxing에 대해 배워보도록 하겠습니다.

 

내부적으로 일어나는 일이기때문에 처음에는 몰라도 상관없지만 퍼포먼스에 좀 더 신경쓰기 시작하면 반드시 이해해야할 개념이라 할 수 있습니다.

 

MSIL 코드를 직접 보면서 Boxing, Unboxing 을 이해해 봅니다.

 

 

Boxing

 

Value 타입의 변수는 Stack에 생성되고 Reference 타입의 변수는 Heap에 생성됩니다.

 

Heap에 무엇인가가 생성될 때 변수는 이 heap에 생성된 객체를 가르키는 4byte "포인터(주소값)"를 할당받게 됩니다.

 

그래서 이 변수를 다른 함수의 매개 변수로 넘길 때는 항상 객체 자체가 아니라 이 포인터만 넘기게 됩니다.

 

value 타입의 변수 경우는 어떤 함수의 매개 변수가 될 경우 이 값의 copy를 만들고 copy를 통째로 넘겨주게 됩니다.

 

여기까지는 c++ 기반 개발자라면 이미 누구나 알고 있는 사항일 것입니다.

 

그러나 닷넷에선 Value 타입의 변수를 Reference 타입의 변수인것처럼 사용하는 경우가 있습니다.

 

그리고 바로 이 때 "Boxing"이 이루어집니다.

 

자 다음과 같은 예를 들어보도록 하겠습니다.

 

public void Method()

{
         ArrayList ar = new ArrayList();

         ar.Add(5);

}

 

ArrayList.Add() 함수의 매개변수로 요구하는 것은 분명 Reference 형인 Object입니다.

 

그런데 value 타입인 integer 값을 함수의 매개 변수로 사용하고 있군요.

 

바로 위와 같은 상황처럼 Value 타입의 변수를 Reference 타입인양 사용할 경우에 Boxing이 일어납니다.

 

IL코드를 확인해 볼까요?

 

.method public hidebysig instance void Method() cil managed

{

     // Code Size: 20 byte(s)

     .maxstack 2

     .locals (

     [mscorlib]System.Collections.ArrayList list1)

     L_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()

     L_0005: stloc.0

     L_0006: ldloc.0

     L_0007: ldc.i4.5

     L_0008: box int32

     L_000d: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)

     L_0012: pop

     L_0013: ret

}

 

AL_0007에서 4바이트 정수 5를 스택으로 로드하고 있습니다.

 

그리고 다음줄에서 우리가 기다리던 boxing을 하는군요.

 

ArrayList에 실제로 저장되는 값은 뭘까요?

 

앞에서 말씀드린 바와 같이 Add()함수의 매개 변수는 Object이기 때문에 5라는 값이 아니라 4바이트의 주소 포인터를 저장해야 한다는 것을 우리는 이미 알고 있습니다.

 

integer object로 변환되는 과정이 필요하겠군요.

 

integer가 가지고 있던 5라는 ''은 힙에 생성한 새로운 주소 공간으로 copy되고 그 값이 저장된 주소를 리턴받습니다.

 

value 타입의 integer(int32) reference 타입의 object가 변환되었습니다.

 

이렇게 닷넷에서 우리가 모르는 사이에 value 타입의 변수를 reference처럼 사용할 수 있도록 해주는 것을 boxing이라고 합니다.

 

 

Unboxing

 

자 그럼 이제 Unboxing 에 대해 알아보도록 하겠습니다.

 

Unboxing은 간단히 boxing의 반대 과정이라고 보시면 됩니다.

 

public void Method()       

{           

ArrayList ar = new ArrayList();

ar.Add(5);

int b;

b = (int)ar[0];

}

 

Unboxing이란 object에 저장된 주소값으로부터 ''을 얻어다 스택에 생성해둔 변수 b copy하는 과정입니다.

 

마찬가지로 IL 코드에 unbox라고 나오는걸 보실수 있습니다.

 

.method public hidebysig instance void Method() cil managed

{

     // Code Size: 34 byte(s)

     .maxstack 3

     .locals (

     [mscorlib]System.Collections.ArrayList list1, int32 num1)

     L_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()

     L_0005: stloc.0

     L_0006: ldloc.0

     L_0007: ldc.i4.5

     L_0008: box int32

     L_000d: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)

     L_0012: pop

     L_0013: ldloc.0

     L_0014: ldc.i4.0

     L_0015: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)

     L_001a: unbox int32

     L_001f: ldind.i4

     L_0020: stloc.1

     L_0021: ret

}

 

쉽게 이해가 가시리라고 봅니다. :)

 

 

정리

 

boxing unboxing을 가능하면 피하는게 좋다는 말을 한번쯤 들어보셨을 겁니다.

 

위에서 보신것처럼 boxing, unboxing이란 닷넷의 배려는 우리가 편하게 프로그램을 짤 수 있도록 했는지는 모르지만

 

IL 코드에서 확인할 수 있는 것처럼 더 많은 과정을 거치고, 메모리를 사용하고, 속도가 느려지게끔하는 효과를 가져올 수 있습니다.

 

boxing하는 과정에서 값을 copy하기 위해 힙에 주소 공간을 확보해야 한다는 것을 기억하실 겁니다.

 

잦은 boxing은 사용되지 않는 리소스를 정리하기 위해 비용이 큰 Garbage Collector가 동작하는 주기를 더 짧아지게 할 수 있습니다.

 

그렇다면 불필요한 boxing을 막으려면? boxing이란 결국 value type의 변수를 reference type object로 암시적으로 변환하는 것입니다.

 

만약 객체가 boxing될 것이 자명하다면 처음부터 object를 사용하면 되겠죠.

 

만약 사용하는 value type의 변수가 32비트 이상이고(크기가 크면 클수록 복사될 때 더 큰 비용을 사용합니다)

 

boxing, unboxing이 자주 일어나는 구조라면 struct(value type)가 아니라 class(reference type) 를 사용하는 것이 유리합니다.

 

때문에 객체의 타입을 정할 때는 객체의 크기와 얼마나 자주 copy되는지를 고려해야 할 것입니다.

출처 : http://tit99hds.egloos.com/540695

나름 정의하면 ajax는 Javascript로 XMLHttpRequest ActivX컨트롤을 통해서 서버와 비동기 통신으로 XML,JSON프로토콜,사용자지정포멧 등으로 데이타 주고받아 DHTML(XSLT)로 웹브라우저내에서 애플리케이션의 기능을 구현하는 기술을 총칭한다고 보면 되겠다. 더많은 ajax라는 용어에 대해 궁금하신 분은 -> http://ko.wikipedia.org/wiki/Ajax

 이 글은 위에서 정의한 ajax의 기술 중에 javascript의 확장된 기능(객체화)을 이용하여 클래스를 설계하는 방법에 대한 설명에 해당하므로 ajax의 포괄적인 의미와
충분히 구분을 가지기를 바란다.

 솔직히 필자도 자바스크립트를 많이 사용 했지만  function이 클래스 선언에 대응된다는 내용은 ajax라는 용어가 광범위하게 퍼진 후이고 객체화와 관련된 스크립트문법을 잘 모르는 부분이 많다. 그래서 본 사이트의 클래스들을 만들면서도 시행착오가 꽤나 많았고 조금 틀린 설명이 있더라도 양해 하시길 바란다.

javascript에 대한 간략한 문법을 먼저 설명 해 본다.
솔직히 script언어의 명세를 찾아볼 수도 있지만 특별히 많은 문법이 없어서 필자의 경우는 코딩을 하면다 이런저런 테스트를 다 해보면서 한다.
function Tab()
{
   var  member = "1";
}
으로 선언 하면 Tab이 하나의 클래스 선언에 해당한다? 라고 생각하지만 글을 읽어가면 아니라는것을 알게 될 것이다. 
뭐 기존의 컴파일러 언어들의 클래스하고 같다고 간단히 생각 할 수도 있지만 사정이 그렇지 못하다.
일반적으로 클래스 내에서 우리는 this라는 포인터를 사용한다. 왜? 이 클래스가 인스턴스화 되었을 때 자신의 포인터를 참조하기 위해서 일 것이다.(아님말구~)
하지만 자바스크립트는 컴파일러의 this처럼 function내에서 this를 확인 해 보면 현재 클래스가 아니라 아마도 window객체가 참조될 것이다.
초기에 필자는 (new Tab()).member하면 Tab의 멤버변수의 값인 1이 참조되는 줄 알았다.. 하지면 아니다 member는 전역변수가 된다. 아래의 예제와 함께 테스트 해보시라.

이거 참 거시기 같지 않은가? 이건 클래스가 아니고 window객체(클래스) 의 멤버함수이지 않은가? 멤버함수 맞다.
그렇다면 왜 클래스라고 하는가? 답은 클래스 처럼 new할 수 있기 때문이다. 한마디로 멤버함수 이면서 클래스 선언으로 사용 될 수 있게 설계를 해 놓은것으로 보면 되겠다. 함수 자체로 클래스정의를 하는것은 아님을 명심하자.

간단한 테스트를 위해 다음 코드와 주석을 보면,
<html>
<head>
<title>가이아타이틀</title>
<script>
function tab()
{
   //alert(this.document.title); //이 코드를 활성화 해보면 this가 window라는거 확인가능
  if(this == window)
     alert("dddd");
 return "1";
}
function initPage()
{
  alert(tab);        // 1) 오호라 놀라워라?
  alert(tab());     // 2) 누구나 아는 결과 "1"
  alert(new tab); // 3)좀 새로운 결과?

}
</script>
</head>

<body onload="initPage()">
<table>
<tr>
<td id="insObj"></td>
</tr>
</table>
</body>
</html>

1)의 결과는 무엇일까?
   난 처음에 object가 리턴될 줄 알았다. 하지만 그 결과는 놀랍다. tab함수의 선언에 해당하는 문자열이 리턴된다.
   한마디로 문자열이란 말인가? 필자도 모른다. 적어도 문자열은 아닌듯하다(간단히 다음코드로 테스트)
var strFun = "function test() { return 1; }";
function initPage()
{
  alert( strFun);
  alert( strFun()); //안먹는다, 당연하다. 단순한 변수에 ()를 붙여서 호출한다고 먹힐리가 없다.
}
결론적으로 alert(tab)을 하면 함수의 정의를 문자열로 뿌리기는 하지만 함수의 이름인 tab과 문자열과는 차이가 있다는 것이다.

2)의 경우는 누구나 아는 기본적인 함수 호출의 결과이다.
3)의 결과는 무엇일까?
   이 경우 초기에 필자는 그냥 object가 alert되는 줄 알았지만 결과는 좀 달랐다
   [object Object] 가 alert된다.
   호잉? 소문자 object, 대문자 Object ?? 도데체 이게 무슨 결과인가?
   처음 소문자 object는 알겠는대 그후의 Object는 도대체 무엇이란 말인가??
   혹시나 해서 alert(Object())라고 찍어본다. 어라..  또 object Object다? alert(new Object()) 와같이 new를 붙이면 어떤결과일까? 어라? 동일한결과??
   의혹이 증폭된다.. 도대체 Object라는 놈이 무엇이란 말인가??
   혹시나 싶어 alert(Object)를 찍어본다... 어라? function Object() { [native code] } 라는 결과가 나온다. 어라 이건 위에서 함수명만 찍었을 때와 비슷한 결과이다.
   음.. 결론을 내자면 잘 모르겠다..ㅎㅎㅎ 아시는분 댓글 부탁~~
   짐작을 하자면 new 함수명()으로 function을 new할 때 시스템 내장객체(함수) Object를 new해서 함수명에 해당하는 객체에 붙여버리는거 같다.
 
즉, 기존 함수객체는 window의 멤버함수이면서 클래스(객체)선언 이고 그 객체를 확장한다는 의미로 Object를 뒤에 붙여버리는듯 하다. 오호라 그럼 실제로 var tabObj =  new Tab()을하면 실재로 리턴되는것은 Object라는 것을 대충 짐작하게 될 것이다.
조금 달리말하면 객체의 형이 Tab인 default Object를 하나 만들어서 리턴해준다고 보면 되겠다.

실질적인 클래스(객체)정의
음... 그렇다면 실재적으로 new했을 때 리턴되는 Object형의 객체는 어떻게 사용하는 것인가????
누가 설계했는지 참 머리 좋다. 기존 단순한 함수기반 스크립트에서 객체로의 확장을 가능하게 설계를 한듯하다.
바로 prototype라는 키워드로 해당 함수가 객체화 되면 확장되는 Object를 채우게 될 객체의 명세를 정의(실질적인 클래스정의)하도록 해 놓은 것이다.
문법은 Tab.prototype = {,,,,} 이다.
참으로 간단하지만 참으로 강력한 문법이다.

 
괄호안은
멤버명 : 초기화값,
.... ,
멤버함수명 : function(파라메타,...)
{

},
.....
로 무한히 클래스 정의처럼 정의 해 가면 된다.
정의한 멤버함수 내에서 this.멤버명으로 값을 참조할 수 있고
var aTab = new Tab() // 실재로 Tab.prototype으로 정의된 녀석이 리턴된다는거 ~
aTab.멤버명 = 값
와 같이 값을 초기화 할 수도있다.

여기까지 이해 했다면 DHTML과 자바스크립트를 좀 다뤄보신 분이라면 어떤 DHTML컨트롤이라도 만들 수 있을 것이다.

본 사이트의 탭 구혀에 대한 본격적인 설명에 들어간다
1. 우선 탭을 구성하는 부분을 생각해 보자
   - 각 탭의 헤더(Header)와 바디(Body)가 한 쌍을 이룬다.(new Tab()했을 때 헤더도 생성하고 바디도 생성하면된다)
   - 각 헤더를 클릭하면 쌍에 해당하는 Body가 나타나고 나머지는 사라져야한다.(display속성이용)
2. 1번의 각 탭들을  담는 객체가 하나 필요하다.(TabGroup이라고 명명한다)
   - TabGroup은 각 탭들이 Add될때마다 배열에 각 탭객체를 담아서 관리한다.
   - 나중에 알게 되겠지만 각 탭이 클릭되었을 때 리턴될 콜백함수를 담을 변수도 빌요하다.
대충 이정도로 간단히 구현의 범위를 잡고 시작하면된다.

구현 1) 탭 객체를 정의한다
function Tab()
{
  ....//뭔가를 정의하고 싶을 것이다. 하지만 여기에 정의하는 변수들은 window전역 변수로 작동하므로 아무것도 정의 할 필요 없습니다.
}
또한 Tab(파라메타1,...)등으로 parameter를 넘겨서 뭔가를 초기화도 하고 싶겠지만 아~~~무 의미없습니다.
그냥 다음에 정의할 prototype을 정의하기 위한 중간 과정으로 보시면 됩니다.

//참고로 visual studio 2008로 javascript를 작성 시 한글 주석달면 IE6.0에서 한글이 깨지면서 자바스크립트 오류를 일으킬 수 있으니 참고하세요
  이거때문에 엄청 시간 낭비T.T
Tab.prototype =
{
   header : null, //contain header object
   body : null, // contain body object
   // 나중에 세부적인 변수는 추가 하고....
   CreateTab : function()
   {
      //탭의 헤더와 바디를 new해서 header,body에 저장
      //
   }
}
위와 같이하면 대충 Tab은 정의 된듯하고 그다음 각 탭을 생성해서 저장 할 TabGroup이 필요하다
function TabGroup(){}
TabGroup.prototype =
{
    count : 0,
    arrayTab : new Array(),
    clickedTab : null,
    callBack : null,
    frame : null,
   AddTab : function(sID,sName) //필요한 parameter넘긴다. 속성으로 지정할지 함수parameter로 넘길지는 편한대로 하면된다.
   {
     //실재로 new Tab()으로 생성해서 arrayTab에 추가하겠죠
   }
}
우선 기본 클래스 정의는 이렇게 하면된다.
이 구조는 일반적인 클래스 설계하는 방법과 같다. 단지 자바스크립트의 특수한 문법이 조금 가미되었을 뿐임을 명심하자.

JSON(JavaScript Object Notation)의 객체정의와의 비교
JSON의 객체정의법
 - 객체는 {} 으로 묶은 문자열로 표현,
 - 객체내의 멤버와 초기값은 멤버명 : 초기값 형태로 표현
    var jsonObject = {};
    //alert(jsonObject );
이 코드를 실행 해보라 객체가 alert된다. 어라? 위에서 함수를 new해서 찍는거랑 같네?
그렇다. 함수를 언하는것과  JSON표기법을 사용하는것과 동일하다는 결론이 나온다.
즉 객체를 함수선언으로 new해서 사용 할 수도 있고 JSON표기법을 이용할 수도 있다는 말이되겠다.
다른 표현으로 설명하면 함수는 객체의 형(클래스)선언이고 JSON표기법은 객체를 바로 기술하는 표기법이다.(그래서 new없이 바로사용)


다음코드를 보자.
var jsonObject =
 { 
  field1 : "field1",
  func1 : function()
  {
   alert("1222");
  }
 };
이런식으로 정의하여 사용하면 속성과 메소드를 포함하는 인스턴스 jsonObject가 만들어진다.
한마디로 위에서 함수정의 객체의 prototype를 이용하여 객체를 확정한 후 new해서 사용하는것과 똑같는 결론이다.

위 코드를 일반 문자열로 묶은경우 eval을 이용하여 JSON객체화 하여 사용 할 수도 있다.
    var jsonStr2 = "{var1 : '111', var2 : '222'}";
    alert(eval('(' + jsonStr2 +')') );
이렇게 앞뒤로 괄호를 붙여서 사용하면 OK,
이것은 웹서비스같은데서 리턴되는 문자열을 JSON형식으로 만들어 리턴한 후 객체화 하여 사용할 때 유용한 방법이다.

객체를 중첩해서 사용가능하다.
    var jsonStr1 = {var1 : '111', var2 : { var2_Sub : 'sub2' }};
    alert(jsonStr1.var2 ); // jsonStr1[0]식으로 배열인덱스로도 접근가능하다.

또한 .을 이용하여 추가적으로 확장해 갈 수도 있다.
var jsonStr1 = {};
jsonStr1.var1 = '111';
jsonStr1.var2 = {};
jsonStr1.var2.var2_Sub = 'sub2';
이런식으 코딩도 가능하지만 그렇게 보기좋은 모양은 아닌듯 하다.

그러면 jsonObject내부에 있는 function()에 대해서 한번 확인해보고 넘어가자.
func1 : function() 으로 정의 된부분은 일반 함수선언과 무엇이 다른가? 뭐 똑같지 않은냐? 라고 생각하겠지만 달랐다.

jsonObject.func1()식으로 일반함수처럼 사용하는것은 똑같다.
그러나 일반함수 선언은 new해서 인스턴스화가 가능했지만 이녀석은 인스턴스화가 되지 않는다.
var obj = new jsonObject.func1(); 하면 어떤 결과가 나올까?
필자는 obj가 func1()의 object객체가 될 줄 알았지만 결과는 아니다. 그냥 jsonObject.func()를 호출하는 것일 뿐이었다.
결론은 멤버함수일 뿐이지 새로운 형(클래스)선언은 아니었다.
(어찌보면 당연하다 이미 jsonObject자체가 메모리에 인스턴스로 올라온것이니까)

여기서 재미난 것이 있다.. 우리가 보통 함수포인터라고 부렸던 콜백기능에 대해서 다을 알 것이다.
자바스크립트에도 그런 기능을 구현 할 수 있다는것에 처음에는 정말 놀라웠다. 다음코드를 보자.
var jsonObject =
 {
  field1 : "field1",
  func1 : function()
  { 
        var Me = this;
        return function()
        {
             //if(this == Me)
             alert("1222");
        }
  }
 };
var funcPointer = jsonObject.func1(); // 이녀석이 C#의 델리게이트 선언에 해당한다고 보면된다.
funcPointer();

이코드를 실행해보면 어떤 결과가 나올까? 1222가 alert된다.
func1을 호출했을 때 function정의를 리턴하면 그 함수의 포인터??(아마도)가 리턴되고 변수에 담아놨다가 콜백함수 처럼 호출 할 수가 있는 것이다. 참으로 놀라운 결과이다.

위 코드에서 주석으로 처리된 부분 //if(this == Me) 을 주석부분을 풀면 1222가 호출되지 않는다는것도 중요하다.
Me에 저장된 this포인터는 jsonObject이고 return function()내부에서의 this는 새로운 함수의 포인터라는 차이점이 있다.
콜백 function내부에서 jsonObject의 포인터를 사용하기 위해서는 위와같은 형식으로 Me변수를 정의하여 내부에서 사용해야함을 잊지말아야 할것이다.

그런데 함수포인터를 어떻게  사용하는 것일까?
C#의 delegate를 사용해 보신분들은 해당 event delegate에 함수를 +연산으로 add하는 것을 알고 있을 것이다.
이녀석도 똑 같다. 리턴된 함수포인터는 임의의 함수 형을 담을 수 있는 녀석이다.
다음과 같이 다른 임의의 함수를 대입만 하면 해당함수를 호출하게된다.
function funcCallBack() { alert('aaaa'); }
var jsonObject =
 {
  field1 : "field1",
  func1 : function()
  { 
        var Me = this;
        return function()
        {
             //if(this == Me)
             alert("1222");
        }
  }
 };
var funcPointer = jsonObject.func1();
funcPointer = funcCallBack ;
funcPointer();

음... 그렇다면 
      return function()
        {
             //if(this == Me)
             alert("1222");
        }
부분에 함수를 파라미터로 넘겨서  코딩을 해두면 어떠한가?
function funcCallBack() { alert('aaaa'); }
function initPage()
{
jsonObject =
 {
  field1 : "field1",
  func1 : function(callBack)
  { 
   var Me = this;
   return function()
   {
         //if(this == Me)
        callBack();
   }
  }
 };

    var test = jsonObject.func1(funcCallBack);
    test();
}
이런 형태의 코딩이 나오게 된다. 함수를 파라미터로 넘겨놓고 필요한 경우에 콜백이 되게 호출 할 수 있는 구조가 가능하다.
여기까지를 이해하면 콜백함수를 구현하는 방식은 다 이해된듯하다.
이제 또 중요한 것이 있다. 해당 콜백함수에 jsonObject의 포인터를 넘겨서 어느객체가 콜백을 호출했느냐를 판단을 해야 하는 경우가 있다.
그때 사용하는것이 apply함수이다.
함수가 호출될 때 호출객체를 바꿔치기 해주는일과  호출 파라미터를 배열형태로 넘기게 해준다는 정도만 알 뿐이다.
최종 콜백구현은 아래의 코드와 같다.
function funcCallBack(param1)

  // 여기에서 this포인터를 참조하게되면 콜백의 호출인 경우 아래 jsonObject의 포인터가된다.
  alert(param1);
}
function initPage()
{
jsonObject =
 {
  field1 : "field1",
  func1 : function(callBack)
  {
                  var Me = this;
   return function()
   {
      var arrArg = new Array();
      arrArg[0] = 'aaa';
      callBack.apply(Me, arrArg);

      if(this == Me)  //this point check
       alert("xxxxx");
   }
  }
 };

    var test = jsonObject.func1(funcCallBack);
    test();
}
여기까지의 내용을 이해했다면 당신은 이제 자바스크립트의 재미에 흠뻑빠져든 것이다.
물론 HTML DOM구조등 기존 자바스크립트 사용법은 다 이해하고 있다는 가정하에서이다.
하지만 스크립트 언어는 한계가 있다. 실재로 객체지향적으로 구현을 해 보면 느끼겠지만 제대로 작동하지 않는 속성이나 메소드도 있다.
객체가 중첩되고 중첩될 수록 그런경우는 더 많아지는것 같다. 물론 필자가 캐치하지 버그일 수도 있지만... 그런 버그를 많이 양산 한다는 것 또한 맘에 들지 않는 부분이다. 주저리주저리.....





오늘 강좌는 Boxing과 Unboxing이라는 개념에 대해서 살펴볼 까 합니다. 이것은 일전의 "형 변환을 기반으로 하는 리플렉션"과 관련성이 있는 내용입니다. 그리하여 실질적인 내용을 따져보면 System.ValueType에 관한 특수한 리플렉션 기술이 Boxing과 Unboxing에 해당됩니다.

 

System.ValueType 형식은 메타 데이터 기반이 아닌 "낮은 수준"의 데이터 형식들의 추상 형식입니다. 여기로부터 파생되었다고 알려지는 주요 데이터 형식으로는, System.Byte, System.Int16, System.Int32, System.Int64, System.Float, System.Double 등이 있습니다. 하지만 이러한 데이터 형식들은 메타 데이터 기반이 아닙니다. 정확한 풀이로는 힙에 할당되며 크기 또한 자유자재로 변형될 수 있는 형식들입니다. 메타 데이터로 표기하는 것은 엄청난 오버로드를 수반하게 되므로 부적절합니다. 하지만 .NET Framework는 이를 매끄럽게 처리하게 되어있는데 그것이 Boxing과 Unboxing이라 불리우는 기술입니다.

 

Boxing과 Unboxing의 의미 풀이부터 해보도록 합니다. 두 단어 모두 Box 라는 키워드를 포함하는데, 쉽게 생각할 수 있습니다. 힙에 할당된 연속적인 데이터를 편리하게 관리하기 위하여 포장을 해놓는다 라는 의미에서 Box를 떠올리면 쉽습니다. 즉, 힙에 할당된 연속적인 데이터를 메타 데이터가 이해할 수 있는 형태로 포장해준다는 의미입니다. 그러면 실제 코딩을 살펴보도록 하지요.

 

int i = 123;

object o = (object)i;

 

위의 두 코드를 살펴보면, 사실 아무런 의미는 없습니다. 하지만 이것이 Boxing의 대표적인 예입니다. 이러한 코딩이 가능함으로서 얻을 수 있는 이점이 대단히 큽니다. Boxing을 가장 잘 활용하는 예는 ADO .NET 관련 클래스들입니다. 데이터 베이스 시스템이 질의에 대한 결과로 반환하는 데이터 형식을 한꺼번에 다루기 위한 방법으로 Boxing과 Unboxing을 복합적으로 활용합니다.

 

i 라는 변수에 123이라는 정수 값을 대입했습니다. 그 다음, o 라는 하나의 추상 객체를 선언하여 형식 변환을 취하였습니다. 코드 상에서는 분명히 형식 변환으로 표기되었습니다만 사실 이 둘은 형식 변환이 일어날 수 없는 관계입니다. object는 메타 데이터로 표기되는 데이터만을 다룰 수 있지만 int는 힙에 할당되는 연속적인 데이터 스트림입니다. 서로 관계가 없지만 이것이 가능했던 이유가 바로 Boxing입니다.

 

int x = (int)o; // Okay

long y = (int)o; // Okay

short z = (int)o; // Error!

 

x는 i와 같은 int 형식이고, y는 int 형식보다 큰 범위의 수를 다룰 수 있는 long 형식이며, z는 int 형식보다는 작은 범위의 수를 다루는 short 형식입니다. 세 동작 모두 object 형식을 int 형식으로 바꾸는 동시에 Unboxing을 수행하게 되었습니다. 즉, object 형식으로 포장된 데이터의 원래 내용물을 대입한 것입니다. 하지만 x, y와는 다르게 z는 컴파일 오류를 낼 것입니다.

 

x는 손실 변환이 일어나지 않았으며 원래의 형식 그대로를 수용하였습니다. y는 원래의 i가 요구하던 정수 범위보다 더 큰 정수 범위를 지원하게 되어 확장 변환이 일어났습니다. 이 경우 두 가지 의미로 해석이 가능한데, 말 그대로 가능성을 위하여 예약된 확장 변환일 수 있지만 반대로 불필요한 공간이 더 많이 할당된 오버헤드 변환이기도 합니다. 하지만 z는 컴파일 오류를 냅니다. 손실 변환으로 다루어질 수도 있겠지만 Unboxing의 정의에 의하면 원래 가지고 있던 데이터 형식보다 범위가 더 적어졌으므로 메모리 구조와는 일치하지 않는 것으로 해석됩니다.

 

int a = o as int; // Error

 

형 변환에 사용하는 as 키워드로 변환을 시도해 보았습니다. 하지만 오류가 나게됩니다. 왜 일까요? as 형식으로 형변환이 가능하다는 것은 메타 데이터에 한정된 내용입니다. 따라서, System.ValueType으로부터 상속받은 모든 형태의 값 형식에서는 as로 형변환을 하거나 as로 Unboxing되지 않게 되었습니다.

 

as를 사용하고자 하였던 의도가 예외를 Throw 하지 않고 null을 대입하려 했던 것이었다면 null을 대입하지 않는 대신 다음과 같은 방법으로 처리하는게 좋습니다.

 

try { int a = (int)o; }

catch { /* 예외 처리 코드 */ }


출처 바람처럼 어디론가 나만의 여행을 가고 싶다 | 바람향기
원문 http://blog.naver.com/aroma_guy/20006951137

메모리 영역

 

- 코드(Code)영역

코드 자체를 구성하는 메모리 영역. 즉 프로그램 명령이 위치하는 곳으로 기계어로 제어되는 메모리 영역이다.

 

- 데이터(Data)영역

데이터가 보관된다. 예를 들면 전역변수(global), 정적변수(static), 그 외 초기화된 각종 배열과 구조체, 자료들이 저장된다.

 

- 스택(Stack)영역

프로그램이 자동으로 사용하는 임시 메모리 영역에 해당합니다. 즉 자동 변수를 저장하거나 함수로 인수를 보낼 때, 복귀 번지를 저장할 때 등에 사용된다. 스택 사이즈는 각 프로세스마다 할당된다. 하지만 프로세스가 메모리에 로드될 때 스택 사이즈가 고정되어 있어, 런타임시에 스택 사이즈를 바꿀 수는 없다. 참고로 VC++6.0에서는 Project Settings에서 스택 사이즈를 바꿀 수 있다.

 

- 힙(Heap)영역

프로그래머가 스스로 할당한 메모리 영역(동적 메모리 영역)을 뜻한다. 즉 C의 함수 중에 메모리를 할당하는 함수인 malloc() 등을 사용하여 할당된 메모리가 힙 영역에 해당된다. 메모리 모델에 따라서 사용하는 함수가 달라지는데, 메모리 할당 때는 malloc(), farmalloc() 함수를 사용하고 재할당 때는 realloc() 함수를, 메모리 해제 시는 free()나 farfree() 함수를 사용한다.

 

언어 책을 보면 스택이나 힙, 큐, 데크라는 말이 나옵니다. 물론 이 말의 뜻을 몰라도 프로그램 짜는데 어려움은 없습니다. 모든 것은 컴파일러라 알아서 해주니까요. 그렇지만 용어의 의미도 모르고 프로그램을 만들려면 조금 답답합니다.

이들 용어는 사용하는 곳에 따라서 의미가 조금 다릅니다. 자료 구조에서 사용할 때와 메모리에서 사용할 때 의미가 조금씩 다릅니다. 자료 구조론에서는 스택과 큐, 데크 등의 용어를 사용합니다. 반면 프로그램을 만들 때는 스택과 힙이라는 용어를 많이 사용합니다.

먼저 우리가 보통 스택과 큐, 힙을 말할 때는 C나 C++의 메모리 구조와 관련된 용어로 사용 합니다. C/C++에서 메모리는 다음과 같은 계층을 이룹니다.

1. 코드(code) 영역
2. 데이터(data) 영역
3. 힙(heap) 영역
4. 스택(stack) 영역

코드 영역은 코드 자체를 구성하는 메모리 영역입니다. 즉 프로그램 명령이 위치하는 곳으로 기계어로 제어되는 메모리 영역입니다. 하위 메모리라고 부르는 가장 낮은 쪽에 있는 메모리 영역입니다. 이 부분은 기계어 부분이므로 프로그래머가 신경 쓸 이유가 없습니다.

데이터 영역에는 데이터가 보관됩니다. 예를 들면 전역(global) 변수, 정적(static) 변수, 그외 초기화된 각종 배열과 구조, 자료들이 저장됩니다.

힙 영역은 프로그래머가 스스로 할당한 메모리 영역을 뜻합니다. 즉 터보C의 함수 중에 메모리를 할당하는 함수인 malloc() 등을 사용하여 배정한 메모리가 힙 영역에 해당합니다. 메모리 모델에 따라서 사용하는 함수가 달라지는데 메모리 할당 때는 malloc() farmalloc() 함수를 사용하고 재배정 때는 realloc() 함수를, 메모리 해제 때는 free()나 farfree() 함수를 사용합니다.

스택 영역은 프로그램이 자동으로 사용하는 임시 메모리 영역에 해당합니다. 즉 자동 변수를 저장하거나 함수로 인수를 보낼 때, 복귀 번지를 저장할 때 등에 사용합니다.

스택과 힙은 사용 용도에 따라서 조금씩 다른 의미로 사용합니다. 예컨대 버퍼 메모리에서 스택고 힙이라는 용어를 사용하면 버퍼 메모리를 구성하는 두 가지 방식을 뜻합니다. 이때 스택은 후입선출(LIFO=Last In First Out) 방식의 버퍼를 말하고, 힙은 선입선출(FIFO=First In First Out) 방식의 버퍼를 뜻합니다.

스택의 경우 후입선출 방식이므로 동작 과정이 푸시(push)와 팝(pop)의 과정으로 이루어집니다. 이를 통해 동작이 한 쪽 끝(top)에서만 일어납니다. 다시 말해서 자료가 들어가는 구멍(입구)과 나오는 구멍(출구)이 하나입니다. 이 때문에 맨 마지막에 들어간 것이 제일 먼저 나오는 겁니다.

큐(Queue)는 프로그램 언어에서 보면 자료 구조의 한 형태로 순차 목록의 한 형태를 뜻합니다. 원소의 삽입은 뒤(rear)에서 이루어지고 삭제는 앞(front)에서 이루어지는 자료 구조를 뜻합니다. 메모리에 적용할 경우 큐는 선입선출 방식을 뜻합니다. 이 때문에 힙과 큐를 혼동해서 사용하기도 합니다. 의미는 같지만 큐는 자료 구조론에서 사용하는 용어고, 힙은 메모리 관련 용어로 사용한다고 보면 됩니다.

데크(Deque)는 Double Ended QUEue의 줄임말로 스택과 큐의 동작 방식을 복합한 방식입니다. 자료 구조에서 선형구조의 목록을 뜻하는 용어로 목록의 양 쪽 끝에서 삽입과 삭제가 가능한 방식입니다.

데크는 입출입 형태에 따라서 한 쪽을 제한할 수 있습니다. 입력 제한 데크라는 방식은 scroll이라고 하는데, 삽입(input)은 목록의 한 쪽 끝에서 이루어지고, 삭제(출력,output)는 목록의 양 쪽 끝에서 이루어지는 방식입니다. 반대로 출력 제한 데크가 있습니다. 출력 제한 데크는 shelf라고 하는데 삽입은 양 쪽 끝에서 이루어지고, 삭제는 목록의 한 쪽 끝에서 이루어지는 방식을 뜻합니다.


티스토리 써야겠다~
C# 메모리 구조 C샵

2008/05/28 08:51

복사 http://blog.naver.com/organiza/70031491336

C#은 메서드, 변수, 클래스 객체 등의 값을 저장하는 3개의 메모리 공간을 갖고 있다.

 

1. 메서드 영역(Method Area):

- 클래스의 메서드에 대한 바이트 코드, 클래스의 전역 변수 등을 할당하는 메모리 영역

 

2. 스택(Stack):

 - 메서드가 실행될 때 매개변수, 메서드 내에 선언된 지역변수, 임시 변수들이 스택 메모리 영역에 저장되며 메서드 실행이 종료되면 스택 메모리는 시스템에 반환함

 

3. Heap:

  - 객체를 사용할때 사용하는 중요한 메모리 공간

     힙 메모리는 new 연산자를 사용해 인스턴스를 생성하는 메모리 공간이다.

     힙에는 클래스, 배열, 문자열 등의 객체 인스턴스를 저장함

 

 

 메서드 영역
 메서드의 바이트 코드
 클래스 변수
 

 

 스택(Stack)
 매개변수
 지역변수
 메서드 실행이 종료되면 스택 메모리는 시스템에 반환함

 

 힙(Heap)
클래스 객체
배열 객체
문자열 객체

 

[출처] C# 메모리 구조|작성자 첫키스


객체지향이란 1편


1. 객체지향의 장점.
객체지향이라는 개념은 무엇보다 알기쉽고,만들기 쉽다는것입니다.
즉 어떠한 컴퓨터 프로그램을 만들때,현실세계에서 생각하는 것과 동일한 사고방식으로의 접근이 가능해졌다는 것이죠. 
그래서 객체지향이라는 개념을 설명할때,  현실세계의  인용이 자연스럽게 나오는 것입니다. 
또한 만들기 쉽다는건 그만큼 유지보수하는데에도 많은 비용을 요구하지  않는다는점 입니다.

2. 객체지향의 중요한 개념 3가지
   1. 상속성 (inheritance)
      객체지향을 말할때 상속성은 가장 중요한 요소들 중 한가지입니다.  상속성은 미리 만들어진

      소스를 가지고 공유하며 재사용하고,  또한 특별한 부분에 대해서는 다시 재정의해서 사용하는

      걸 말합니다.  즉, 개발하는데 있어서, 많은 부분을 생략할 수 있다는 거죠.또한, 어느부분에

      오류가 있을때,  한부분의 수정만으로,  그 소스를 이용해 만든 모든 소스의 오류를 방지할

      수 있다는 장점을  또한 가지고 있습니다.
   2. 다형성(Polymophism)
      뒤에서 다시 머리 터지게 설명 드리겠지만 맛뵈기로 간단하게나마 말씀드리자면 상속을 받은

      것을 그대로 사용하지않고 입맛에  맞게 바꾸어줄수 있도록 하는것이 다형성입니다.  

      OVERRIDEN의 개념입니다.  OVERRIDEN은  재사용성으로 통하기도 하는데 그말이 맞는 거

      같습니다. 뒤에가면  OVERRIDEN 않쓰고는 SOURECE가 만들어 지지 않습니다. 특히 상속을

      받은 경우는 더 하지요. 


   3. 캡슐화(Encapsulation)
      캡슐화라고 하는것은 어떠한 데이타를 보호할 수 있다는 점입니다. 즉 어떠한 소스를 만들었을

      때, 그 소스의 데이타를 보호할 수 있고,  보호 할 수 있다고 하는건 그 소스를 사용하는 입장에

      서보면,  더욱더 안정된(또는 검증된) 소스를 사용한다는 것입니다. 같은 개념으로 data hiding

      이라고 하는데 대부분의 번역서에선 데이타 은닉화라고합니다. 말이 좀 이상하죠? 이게 문제

      입니다. 차라리 영어를 그대로 보는게 속편하죠(음.. 옆길로 셌군...)  
                
객체지향의 중요한 개념3가지에 대해서 간략하게 나마 정리를 했습니다.  벌써 눈치들을 채셨겠지

만 저놈들은 따로따로  때어 놓고는 생각할 수가  없습니다. 상속이 이루어져야 다형성을 써먹을수

가  있고 상속성을 쓰기위해서는 데이타가 믿을 만해야 하는데 그걸 만들어 주는것은 캡슐화 입니

다.  그리고 완벽한 캡슐화를 이루기 위해서는 상속성과  다형성이 뒷받침이 되어야 함은 말할 필요

도 없지요. 예를 보면서 좀더 자세하게 이야기 해보겠습니다.(사실 캡술화가 젤루 만만해여^^;)


                class Date
                {
                        int day;
                int monty;
                    int year;
                }


 지금 제가 아주 간단하게  Date라는 class를 만들어 보았는데, 이 클래스를 가만히 생각하게 되면

 이런 점이 있을 수가 있겠죠. 지금 date라는 클래스는 날짜를 저장하기 위해서 만든건데 일단 day

 라는 변수를 살펴보면 31보다 더 커다란 숫자가 저장되면 날짜를 잘못저장하게되는 거겠죠? 

  그러니깐

   Date d = new Date();


  하고 객체를 생성한 후 d.day = 40; 이라고 하게 되면 우리가 생각하는 개념상 잘못된 날짜가 만들

  어 지겠죠? 이럴때 이런 변수들(외부에서 임의로 조작되었을때 원하지 않는결과가 나오는것들

  또는 잘못된 결과가 나오는것들) 에대해서 외부로 부터 접근 제한을 시키는 것이 바로

  encapsulation이라고  생각하시면 됩니다. 그래서 이런 캡슐화를 어떻게 구현하게 되냐면..


        class Date
        {
                private int day;
                private int month;
                private int year;
        }


라고 만드는 것이지요. 여기서 private는 접근제한자라 불리는 것인데. Date라는 클래스 외부에서의

접근을 막는 것입니다.즉


        Date d = new Date;


한 후에 d.day = 40; 이라고 하면 에러가 나게 되는 것이죠.. 즉 외부로부터 어떠한 데이터를  보호

한다는 의미죠. 그런데 이렇게 보호만 한다고 해서 되는건 아니겠죠? 보호하는것까지는 좋은데

일단 만들어 놓은걸 사용하지 못하게 되는 것이니깐요. 그래서 이렇게 보호해놓은 데이타를 메소드

를 통해서 접근을 허락하는 것입니다.


        class Date
        {
                private int day;
                public void setDay(int targetDay)
                {
                        day = targetDay;
                }
        }


 제가 설명하기 쉽게 일단 변수를 하나로 줄였습니다.  자 그럼 설명을 계속하면 보시는 대로 day라

 는 변수를 외부에서 접근하지 못하게 private로 선언한 다음 setDay라는 메소드를 제공해 주는것이

 죠.그런데 위에 것만 보면 그전것과 크게 달라진 점이 없죠? 지금 나온 에제도 day라는 변수에 잘

 못된 값이 들어갈 수 있을테니깐요. 그래서 메소드를 제공하긴 하는데 그냥 제공만 하는 것이

 아니라.
 

       class Date
        {
                private int day;
                public void setDay(int targetDay)
                {
                        if(day==targetDay)
                        else
                        {
             // 이곳에는 잘못입력했으니깐 다시 입력하라는 식의 코딩이 들어가면 되겠죠.
                        }
                }
        }


이런식으로 만드는 겁니다. 그래서 다시 정리를 하자면 캡슐화라는것이 어려운 개념은 아닙니다.

일단 외부에서 조작이 되면 안되는 그런 변수에 대해서 private라고 선언한후 대신 메소드를 통해서

접근할 수 있도록 해주는 것이죠. 그리고 그 메소드에는 어떠한 검사부분이 들어가면 됩니다. 지금

넣으려는 값이 제대로 된것인지 아닌지를.  그래서 제대로 된것이라면 그냥 넣으면 되는 거구요. 제

대로가 아니라면 어떠한 처리부분이 들어가면 되겠죠?
  
1. Creating an Object


보통 자바에서 primitive data type(자바의 기본 데이타 타입을 선언하게 되면 실제적인 메모리에

할당되게 됩니다. 그렇지만 primitive data type이 아니라면(바로 reference type일 경우) 실제적인

메모리 공간에 할당되는게 아닙니다.  그런 레퍼런스 타입은 어떠한 주소값이 저장될 공간이 만들

어 지는 것이고, 실제로 다른곳에 실제적인 Object 가 저장이 되는것 이지요. 이런걸 보면 어느

정도 C에서 말하는 Pointer와 비슷합니다. 하지만 자바는 Pointer를 제공해 주지 않지요. 그져

reference라고 말하는것 뿐. 그리고 Pointer 연산은 안됩니다.(해도 되긴한데 엉망이 되어 버리죠)

그건 프로그램의 견고성  때문이지요. 뒤에서 자바의 특징을 말씀드릴때  다시한번 정리하겠지만

자바는 performance보다는 완벽한 객체지향을 목표로 만들어 졌으며 또한 서버에서 돌아가는 프로

그램 개발이 목적이였으므로 상당한 수준의 보안성과 안전성을 가지도록 만들어 졌습니다. Point를

써보신분들은 아시겠지만 이놈이 시스템을 아예 날려버리기도 하니까요 각설하고 객체를 만들때는

밑에서 처럼 new keyword를 사용 하시면 됩니다.

        1) MyClass m = new MyClass();
                Or
        2) MyClass m;
                m = new MyClass();

첫번째 예제는 선언과 동시에 Object를 하는 것이고, 두번째 예제는 선언과 Object생성을 나누어서

하게 되는것이죠.  두 예제의 다른점은 별반 없다고 생각하셔도 상관없습니다. 그리고 이렇게 만들

어진 Object에 접근을 하려면 dot 를 사용합니다. "variable dot  member"의 형식입니다. 예를 들면

m.day 라는 식이죠. 바로 m이 어떤 객체를 가리키는 reference이구요, day가 그 객체가 가지고 있

는 member variable이 되는 거죠. 그럼 실제로 한번 예제를 해보도록 하죠. MyDate라는 class를

만들어 보도록 하겠습니다.

        class MyDate
        {
                int day;
                int month;
                int year;
        }

이렇게 만든 다음 javac로 compile하시면 되겠지요.
그다음 사용을 하시려면 객체를 만들어야 겠지요. 그래서 MyDate를 사용하는 class도 만들어

보겠습니다.

        class TestMyDate
        {
                public static void main(String args[])
                {
                        MyDate m = new MyDate();
                        m.day = 3;
                        m.month = 4;
                        m.year = 2000;
                        System.out.println("나의 생일은 " + m.year + "년 " +  m.month + "월 " + m.day +"일 입니다.");
                }
        }

위의 TestMyDate를 실행시켜 보면 "나의 생일은 2000년 4월 3일 입니다." 라는 문장이 출력될 것입

니다. 소스를 설명드리면 3번째 줄에서 MyDate라는 class를 사용하기 위해 Object를 만들었습니

다. 그리고 4번째 줄에서 6번째 줄까지m.variable의 형식을 사용해 member variable에 값을 할당

하는 것이지요. 그리고 나서 7번째 줄에서 그런 값을 가져와서 출력하게 되는 것입니다. 이런

식으로 만들어진 Object의 값을 가져오고 할당할때는 referenceName.variable의 형식을 사용하면

되는 것입니다.


객체지향이란 2편


오늘은 객체지향 언어에서 사용하는 "is a" 관계에 대해 알아보도록 하죠. 일단 간단하게 말씀드리

면 상속관계 라고 할 수 있습니다. 상속관계에서의 상위계념은 하위개녀들을 포괄할 수 있는 내용

들이 들어갑니다. 예를 들어 포유류를 볼때 포유류는 젖먹이는 동물을 말합니다. 따라서 가장 상위

계념은 젖먹인다가 포함되는건 당연하겠죠. 포유류라는게 이런 동물들의 공통점을 뽑아 만든 개념

이니깐요. 즉 우리가 프로그래밍을 하다 보면 이런  관계를 가진 클래스들을 만들게 되는데.. 이런

관계에서 포유류를 상위클래스, 그리고 사슴, 사람 그리고 토끼  를 하위클래스로 보면 되는 것이

죠. 이럴때 우리는 이런 말을 사용합니다. 사슴은 포유류다. 또는 사람은 포유류다라는 말을. 즉 우

리가 다음과 같은 클래스를 만들게 되면

                                  Employee
                                     |  
                                     |  
                                  Manager

즉 코딩은 다음과 같겠죠.
        
        class Employee
        {
                String name;
                int salary;
                int ssn;
        }


        class Manager extends Employee
        {
                String managerGroup;
                // any coding...
        }
        
이럴때 객체지향언어에서는 Manager is a Employee 라는 말을 사용합니다.위의 예와 같은 식이

죠.따라서 이런 "is a"관계가 바로 상속관계라고 생각하시면 됩니다.위에서 설명드리지 않은 것중에

extends라는 것이 있죠.이것이 바로 상속을 할때 사용하는 keyword입니다.  상위에 있는 클래스

(Employee를 말하죠.)의 모든것을 하위에  있는 클래스(Manager) 가 물려 받는 것이죠. 즉

Employee에 있는 Class에 있는 name, salary, ssn같은 것들을 Manager또한 사용하기 때문에

Manager를 새로 처음부터  만드는 것이 아니라 Employee를 상속받고 자신만의 변수(man
agerGroup)를 선언해서 사용하는 겁니다.  물론 재사용별骸?관련이 있겠구요. 자바에서는 단일

상속만을 지원합니다. 즉 모든클래스의 상위클래스는 반드시 하나만이 존재할 수 있다는 것입니다.

물론 그 상위클래스위의 상위클래스는 존재할 수 있겠죠. 바로 위가 하나라는 말입니다...물론 아시

죠? 또한 어제 했던 생성자와  연계시켜서생성자는 상속되질 않습니다. 당연하겠죠. 왜냐하면,  생

성자라고 하는 것이 하는일이 멤버 변수의 초기화를  하게 되는건데 상속을 받아서 새로운 멤버를

선언하게 될텐데.  그런건 자신의 클래스 안에서 해야되는거겠죠?  또한 생성자를 만드는 법이

return type이 없고,class의 이름과 같아야 하기 때문에 상속받아봐야 자신의 클래스에서는 생성자

의 역활을 할 수가 없겠죠?



객체지향이란 3편

객체의 다형성

객체지향의 진주이자 마지막 관문이며 가장많이 사용되며 가장많은 질문과 회의를 낳게하는 다형

성에 대해 적으며 간략한 객체지향에 대한 글을 접을까 합니다

1. 다형성(polymopism)
    A. 정의
         Super class type의 Reference변수로 sub class type의 객체를 참조한다. 쉽죠? ^^; 예를

         봅시다.
        예)
                abstracte class Employee
                {
                        String name;
                        float bs;
                        double salary;
                        abstracte public void setSalary();
                   //이렇게 하면 반드시 밑에서 overriden해야한다.
                  /* abstracte 선언은 밑에서 객체로 생성하지 못하게할 내용을  나타낼때 사용한다.
            또한 abstracte클레스라고 해서 반드시 포함된 모든것이 다 abstracte가 되는건 아니다.
                        */
                }

                class SalesEmployee extends Employee
                {
                        public void setSalary()
                        {
                                salary = bs*1.5;
                        }
                        public void aa()
                        {
                                System.out.println("aa");
                        }
                }

                class RegularEmployee extends Employee
                {
                        public void setSalary()
                        {
                                salary = bs*1.3;
                        }

                        public void bb()
                        {
                                System.out.println("bb");
                        }
                }
일단은 예제 설명은 접어두고 예제의 내용은 기억하기 바란다.
자아 이제 심오한 이야기를 하겠다.
                SalesEmployee s[] = new Employee[2];


이문장이 실행되면 결과는? 맞춘분께는 아무것도 못드림다. 결과는 에러. 그렇다면 아랫걸보자.


                Employee e[] = new SalesEmployee[2];


이문장은 정상적으로 실행이된다. 왜? 소스코드를 보면 SalesEmployee가 기억장소에 저장되면은

name, bs, salary, setSalary(), 그리고 aa가 기억되어진다. 근데 위의 문장은 Employee type으
로 객체를 선언했다. 그러면 레퍼런스하는곳이 자신이 레퍼런스하고자 하는 숫자보다 작으므로
에러가 발생한다. 밑에 문장은 그런 이유로 가능한것이다.
기억하자. sub class type의 레퍼런스로 super class를 참조할 수 없다.
이제 다형성을 정의헤보자. 객체지향이 제사용성의 측면을 무쟈게 강조하고 있다는건 다 아실것
이다. 그럼 그런 연유에서 상속성이 나오게 된것도 알것이다. 그렇다면 변화를 주지 않고  사용
할 수 있는 것의 한계는 불보듯 뻔한것이다. 하나의 선언되어진 객체를 여러가지형태로 재정의
해서 사용할 수 있는 것이 다형성이다.

 *overriden


 재정의라고도 한다. 위의 소스를 보자 실제 메인부분에서(아직은 없지만) setSalary를 호출한다
면 무엇이 호출될까? 정답은 밑에서 정의한 것이 호출된다. 어떤 메쏘드를 호출할 때 상속이 이
루어졌다면 그 상속의 틀에있는 생성자들에 대하여 override검사라는것을 jvm이 한다.   그레서
 맨 나중에 재정의 된것을 사용하게 되는것이다. 왜? 상상을 해보라. 기껏 재정의 해놓은게 늘쌍
 부모클레스의 것만 사용된다면 허무하지 않겠는가? 위 소스를 완성해보자.

                abstracte class Employee
                {
                        String name;
                        float bs;
                        double salary;
                        abstracte public void setSalary();
                }

                class SalesEmployee extends Employee
                {
                        public void setSalary()
                        {
                                salary = bs*1.5;
                        }
                        public void aa()
                        {
                                System.out.println("aa");
                        }
                }

                class RegularEmployee extends Employee
                {
                        public void setSalary()
                        {
                                salary = bs*1.3;
                        }

                        public void bb()
                        {
                                System.out.println("bb");
                        }
                }

                public class PolyTest
                {
                        public static void main(String args[])
                        {
                                Employee e[] = new Employee[2];
                                e[0] = new SalesEmployee;
                                e[0].bs=1000000;
                                e[0].setSalary();
                                e[1] = new RegularEmployee;
                                e[1].bs=1000000;
                                e[1].setSalary();
                                
                                System.out.println(e[0].salary+":"+e[1].salary);
                        }
                }

결과는? 직접해보시기를....
그리고 객체지향에 대해 궁금하신분은 아래 싸이트를 가보시기 바란다.
 www.omtgroup.com


프로그래밍 격언모음

1. "오늘까지"라는 말은 "내일 아침까지"라는 말이다.



2. 프로그램은 내가 원하는대로 움직이지 않는다. 타이핑대로 움직인다.



3. 요구 사양은 프로그램을 완성한 후에 추가된다.

기본 사양은 완성품을 고객이 보고 나서 결정된다.

상세 사양은 사용자가 프로그램을 사용해 본 이후에 결정된다.



4. 소프트웨어 설계에는 두 개의 방법이 있다.



하나는 결함이 있을 수 없을 정도로 단순하게 만드는 방법이다.

다른 하나는, 분명한 결함을 눈치채기 어려울 정도로 복잡하게 만드는 방법이다.



5. 코드는 개발 현장에서 사용하는 것이 아니라 납품처에서 사용하는 것이다.

디버그는 납기일까지 하는 것이 아니라, 납품된 이후에 하는 것이다.



6. 프로그래머를 죽이기 위해서는 칼이 필요없다. 프로그램의 요구조건을 3번만 바꾸면 된다.



7. 다른 사람을 믿으라. 그 사람이 해결해줄지도 모른다.

주의사항 - 먼저 자신을 의심해라.



8. 개발에 마지막은 없다. 출시만이 있을 뿐이다.



9. 클라이언트의 요구사항이 제 아무리 뒤늦게 추가되어도 납기일은 변하지 않는다.

이것을「납기 불변의 법칙」이라고 한다.



10. 우리의 고객들은 물과 기능추가를 공짜라고 생각하고 있다.



11. 주머니가 짠 고객일수록 잔소리가 많다.



12. 개발 스케줄은 산수를 무시하며 짜여진다. 영업과는 1+1=2를 이해하지 못하는 사람의 모임이다.



13. 한 명이 쓰러지면 모두가 쓰러진다.



14. 버그가 너무 심하다? 걱정마라. 어느 순간 그것은 기본 사양이 될 것이다.



15. 좋은 설계는 한 명의 천재보다 세 명의 범재를 요구한다.

나쁜 설계는 백명의 범재보다 한 명의 천재를 요구한다.



16. 고객에게 시스템 엔지니어는 부하이며, 프로그래머는 가축이다.

시스템 엔지니어에게 고객은 돈이다.

프로그래머에게 고객은 보이지 않는 악성 바이러스다.



17. 돈과 시간만 있으면, 그 어떤 시스템이라도 만들 수 있다고 생각하는가?

웃어라. 그 기회는 영원히 주어지지 않는다.



18. 품질은 사양 변경의 수와 규모에 의해, 얼마나 열화될지 결정된다.



19. 영업과는 공상이 실현된다고 생각하는 몽상가이다.

시스템 엔지니어는 넘을 수 없는 벽이 없다고 믿는 모험가이다.

프로그래머와는 몽상가와 모험가에 의해 칠흑의 바다에 내던져진 표류자이다.



20. 유능한 프로그래머가 프로그램 설계개념도를 받아들고 최초로 하는 일은, 프로그램의

목적을 이해하는 것이다. 그리고 그 다음으로 하는 일은, 지정된 방법과 시간 안에는

도저히 그 목적을 완수할 수 없다는 사실을 시스템 엔지니어에게 이해시키는 일이다.



21. 프로그램이란, 운과 감에 의해서 작성되는 기적이다.

운과 감이 없다면, 그 기간 내에 그러한 목표를 실현될 수 있을 리 없다.

따라서 사양 변경은 기적에 트집을 잡는 건방진 행위이며, 사양 추가는 기적이 두 번

일어날 것으로 믿는 무모한 행위이다.



22. 시스템 엔지니어는 지구력, 프로그래머는 순발력.



23. 정시에 퇴근하면, 일이 늘어난다.



24. 완벽한 프로그램은 완벽한 시간과 돈을 필요로 한다.

미국의 국가 예산을 무제한으로 사용하는 NASA마저도, 아직 시간과 돈이 부족하다고 한다.



25. 눈으로 훑어볼 틈이 있다면 움직여라. 뇌세포보다 CPU가 더 해석이 빠르다. 그리고, 그 사이,

쉴 수 있다.



26. 불편함을 버그라고 부를 것인가, 사양 상의 제한 사항이라고 부를 것인가는 남겨진 개발일자와

납기일에 의해 결정된다.



27. 정장 대신 캐쥬얼을 입고 출근하는 "캐쥬얼 데이"를 세간에서는 휴일이나 공휴일이라고 부르는

것 같다.



28. 프로그램은 머리로 기억하지 않는다. 몸으로 기억한다.



29. 내일 쉴 수 있다면 오늘 죽어도 괜찮다.



30. 고객은 거짓말을 한다.

영업은 꿈을 말한다.

시스템 엔지니어는 공상을 이야기한다.

프로그래머는 과묵해진다. (혼잣말은 많아진다)



31.「네, 할 수 있습니다」라고 말하기 전에 10초만 곰곰히 다시 생각해보라.



32. 프로그래머는 1분 생각하고 1일을 코딩에 소비한다.

1시간 생각하고 1시간 코딩하는 대신에 말이다.



33. 납품 이후의 디버그는 버그를 부른다.



34. 세 개의 디버그는 하나의 버그를 낳는다. 이것을 버그의 엔드리스 루프라고 한다.



35. 안 좋은 예감은 반드시 적중한다. 그러나 프로그래머는 그 안 좋은 예감에 반응하지

않는다. 그것은 시스템 엔지니어의 일이다.



36. 아수라장을 해결할 수 있는 방법은 오직, 고객이 돈을 지불하는 것 뿐이다.



37. 아마추어는 버그발견의 천재이다.



38. 아, 그건 마이크로소프트에서만 가능한 주문입니다.



39. 프로그래머가 불만이라고 생각하는 부분은 고객도 반드시 불만이라고 생각한다.



40. 건강하기 때문에, 건강을 해친다.



41. 그건, 당신이 말한 요구조건입니다만.



42. 아, 개발실의 창문은 안 열립니다. 그 이유는 옛날에 한 프로그래머가 그 창문에서···



43. 고객은 최악의 사태를 믿지 않으며, 그 사태에 대한 준비를 악질적인 비용청구라고 생각한다.

시스템 엔지니어는 최악의 사태를 대비하고 준비하려 한다.

프로그래머는 최악의 사태를 누구보다 잘 예상하지만, 무시한다.



44. 만약 다른 직업을 갖게 된다면, 정시퇴근을「도망」이라고 부르지 않는 직업이 좋을 것 같다.



45. 시스템 엔지니어가 프로그래머에게 말하는「상식」은 3시간마다 변한다.



46. 최소한 자기가 쓴 시방서는 읽어주세요.



47. 고객이 시스템 엔지니어에게 사랑받는 방법은, 시스템 개발에는 시간이 곧 돈이라는 사실을

깨닫고 빨리 최종요구조건을 확정하는 것이다.



SE가 고객에게 사랑받는 방법은, 프로그래머에게 미움받는 것이다.



48. 납기일이란, 작업현장이 우리 회사에서 고객의 회사로 바뀌는 날을 의미한다.



49. 가끔 일어나는 버그는 버그가 아니다. 스펙이다.



50. 개발비의 30%는 프로그램의 요구조건을 확정하는데 사용된다.

개발비의 30%는 프로그램의 요구조건을 변경하는데 사용된다.

개발비의 30%는 프로그램의 버그를 잡는데 사용된다.

개발비의 10%만이 프로그램의 개발에 사용된다.
*폼 등에서 enter키로 인한 불필요한 동작 회피하기 : Netscape에서는 다르게 처리해야 함.
*textarea, button, submit, cancel 외의 부분에서 Enter키 입력하면 Tab으로 전환시켜줌.


<body onKeyDown="javascript:event.keyCode =(event.keyCode == 13) ? ('textarea:button:submit:cancel:'.match 13:9):event.keyCode">
Sub ... End Sub, Function ... End Function  둘의 차이점

공통점
- 특정 부분의 작업을 수행한다.
- 계산이나 작업의 처리를 위해서 필요한 값을 넘겨받을 수 있다.

차이점
- Sub 는 작업을 처리하지만, 결과값을 리턴시키지는 않는다
- Sub 는 작업의 처리를 위해서 일정한 자료를 받거나 받지 않을 수 있다.
- Function 은 작업을 수행하고, 결과값을 리턴한다.
- Function 은 작업의 처리중에 필요한 자료를 함수에 전달해야 한다.
- Function 은 작업의 결과를 리턴하기 위해서는 함수와 같은 명칭의 변수명에 값을
  넣어서 되돌려 보내야 한다.

호출예
- Sub : <% Call Sub_name(값)%>
- Function : <% 변수명 = Finction_name (값)%>
이 방법은 위 두가지 방법과 달리 자바스크립트를 이용하는 것인데 새로운 창의 디폴트 속성을 사용하는 것이 아니고 속성을 변경한 브라우저 창을 띄우고 싶을 때 유용한 기능이다.

<SCRIPT>
function openTarget (objForm, strFeatures, strWindowName) {

// 새로운 창 이름이 없으면...
if (!strWindowName)
// formTarget이란 문자열에 현재 시간을 붙인 이름 부여
strWindowName = 'formTarget' + (new Date().getTime());

// 폼의 target 속성 부여
objForm.target = strWindowName;
open ('', strWindowName, strFeatures);
}
</SCRIPT>
...
...

<form name="myForm" method="post" action="formProcess.asp"
ONSUBMIT="openTarget(this, 'width=300,height=300,resizable=1,scrollbars=1'); return true;">
...
...
</form>


<form>의 onsubmit 이벤트 발생시 openTarget이란 사용자 정의 함수를 호출한다. 이 함수에서 새로운 창을 띄우는데 디폴트 창이 아니라 가로, 세로 크기 등을 조절한 창을 띄운다. 위의 openTarget이란 함수에서 가장 핵심은 objForm.target 부분이다. 즉 폼 객체의 target 속성에 새로운 창 이름을 지정해 주면 되는 것이다.

자바스크립트에서 새로운 창을 열 때의 속성에 대해 좀 더 자세히 알고 싶은 사람은 다음 글을 참고하기 바란다

create table tablenameA(n int)

-------------------------------------------

declare @tablename sysname,@sql nvarchar(4000),@ret int

set @tablename = 'tablenameA'
set @sql = N'select @r = count(*) from ' + @tablename
exec sp_executesql @sql,N'@r int output',@r = @ret output

select @ret

/*
------------
0
(1 적용됨)
*/

+ Recent posts