ByteBuffer 사용법



ByteBuffer 사용법에 대해 알아보겠다. 이렇게 ByteBuffer를 자세히 설명하는 이유는 java에서 NIO를 이용하기 위해서다. 보통 자바가 C에 비에 느린 이유중 하나가 IO가 JVM 내부에 IO버퍼를 두었기 때문이다. 


ByteBuffer 초기화와 사용법



[전체 예제]

import java.nio.ByteBuffer;


public class NioBuffer1 {


public static void main(String[] args) {

ByteBuffer buf = ByteBuffer.allocate(10);

System.out.println("position[" + buf.position() +"] Limit["+ buf.limit()+"] Capacity["+buf.capacity()+"]" );

buf.mark(); //나중에 찾아 오기 위해 현재 위치를 지정해 둔다. (현재 위치는 0 )

//순차적으로 데이터 넣기 -> 데이터를 넣을 때 마다 position이 바뀐다.

buf.put((byte)10);

System.out.println("put result -> position[" + buf.position() +"]");


buf.put((byte)11);

System.out.println("put result -> position[" + buf.position() +"]");

buf.put((byte)12);

System.out.println("put result -> position[" + buf.position() +"]");

//mark 해 두었던 위치로 이동

buf.reset();

System.out.println("put reset -> position[" + buf.position() +"]");

System.out.println("");

System.out.println("데이터 들어간 결과 확인");

//데이터를 get 할 때 마다 position이 바뀐다.

for( int i = 0 ; i < 5 ; i++ ) {

System.out.println("position[" + buf.position() +"] value["+ buf.get() + "]");

}

//지정한 위치에 데이터에 넣기

buf.put(2, (byte)22);

buf.put(3, (byte)23);

buf.put(4, (byte)24);

System.out.println("");

System.out.println("데이터 들어간 결과 확인");

for( int i = 0 ; i < 5 ; i++ ) {

System.out.println("position[" + i +"] value["+ buf.get(i) + "]");

}

}

}


[실행 결과]

position[0] Limit[10] Capacity[10]

put result -> position[1]

put result -> position[2]

put result -> position[3]

put reset -> position[0]


데이터 들어간 결과 확인

position[0] value[10]

position[1] value[11]

position[2] value[12]

position[3] value[0]

position[4] value[0]


데이터 들어간 결과 확인

position[0] value[10]

position[1] value[11]

position[2] value[22]

position[3] value[23]

position[4] value[24]


[메모리 크기 설정 및 초기화 된 값 확인]

10자리 byte 만큼 메모리 공간 확보

ByteBuffer buf = ByteBuffer.allocate(10);

System.out.println("position[" + buf.position() +"] Limit["+ buf.limit()+"] Capacity["+buf.capacity()+"]" );


[순차적으로 데이터 넣기]

position 0~2까지 순차적으로 데이터가 10, 11, 12를 넣는다. 이때 position의 위치도 바뀐다.

buf.put((byte)10);

System.out.println("put result -> position[" + buf.position() +"]");


buf.put((byte)11);

System.out.println("put result -> position[" + buf.position() +"]");

buf.put((byte)12);

System.out.println("put result -> position[" + buf.position() +"]");


[순차적으로 데이터 빼기]

position 0~4까지 순차적으로 데이터가 뺀다. 이때 position의 위치도 바뀐다.

for( int i = 0 ; i < 5 ; i++ ) {

System.out.println("position[" + buf.position() +"] value["+ buf.get() + "]");

}


[특정 위치에 데이터 넣기]

position 2에는 22, 3에는 23, 4에는 24를 넣는다. 

buf.put(2, (byte)22);

buf.put(3, (byte)23);

buf.put(4, (byte)24);


[특정 위치에 데이터 빼기]

position 0~4까지 데이터가 뺀다. 

for( int i = 0 ; i < 5 ; i++ ) {

System.out.println("position[" + i +"] value["+ buf.get(i) + "]");

}


반응형

[Design Pattern] Factory Method 패턴



팩토리 패턴을 이해하기 위해서는 우선 템플릿 패턴을 알아야한다. 왜냐하면 템플릿 패턴에 인스턴스 생성하는 부분까지 추상화 시켰기 때문이다.

팩토리 패턴은 처리 골격을 만들고 상속 받은 클래스가 구체적인 처리를 구현해 놓습니다. 또한 인스턴스를 생성하는 부분까지 맡겼기 때문에 해당 클래스를 호출하는 부분에서는 따로 인스턴스를 만드는 과정을 없앴습니다.


팩토리 메소드 패턴



다목적 공장이 있습니다. 이 공장을 가지고 있으면 철강, 차, 베터리 등등 모든 것을 만들 수 있다. 이 공장을 이용해 차를 만드는 과정을 프로그램화 해보겠다. 다목적 공장에 해당하는 Framework 패키지 안에 Factory와 Product가 있다. 이 공장들을 이용해 차를 만드는 것은 Car 패키지에 Factory를 상속 받은 CarFactory가 Product를 상속받은 Car를 만드는 과정을 알아보겠다.


[클래스 다이어그램]




[framework 패키지에 Product 구현]

다목적 공장에서 생산되는 상품 규격을 정의해 놓은 추상화 클래스 이다.

해당 규격에만 맞게 구현 할 수 있으면 Factory에서 어떠한 제품을 만들어 낼 수 있다.

package framework;


public abstract class Product {

public abstract void use();

}



[framework 패키지에 Factory 구현 ]

Factory 추상화 클래스에서는 Product를 생성한다. 이 클래스를 상속 받은 클래스는 해당 규격에 맞게 구현만 하면 어떠한 공장도 만들어 낼 수 있다.


package framework;


public abstract class Factory {

public final Product create(String owner) {

Product p = createProduct(owner);

registerProduct(p);

return p;

}

protected abstract Product createProduct(String owner);

protected abstract void registerProduct(Product product);

}



[car 패키지에 Car 클래스 구현]

Product를 상속 받아 실제로 차에 대한 기능을 구현 한다.


package car;

import framework.*;


public class Car extends Product {

private String owner;

Car(String owner) {

this.owner = owner;

System.out.println(owner + "의 차를 만듭니다.");

}

@Override

public void use() {

System.out.println(owner + "의 차를 이용합니다.");

}

public String getOwner() {

return owner;

}

}



[car 패키지에 CarFactory 클래스 구현]

Factory를 상속받은 CarFactory 클래스는 Car 클래스 인스턴스를 생성 한다. 더블어 ArrayList 클래스를 이용한 생성한 Car 주인에 대한 관리도 가능하다.


package car;

import framework.*;

import java.util.*;


public class CarFactory extends Factory{


private List owners = new ArrayList();

@Override

protected Product createProduct(String owner) {

return new Car(owner);

}


@Override

protected void registerProduct(Product product) {

owners.add(((Car)product).getOwner());

}

public List getOwners() {

return owners;

}


}



[Main 구현]

만들어 놓은 차 공장을 이용해 차를 생산해 보자.


import car.*;

import framework.*;


public class Main {


public static void main(String[] args) {

Factory factory = new CarFactory();

Car car1 = (Car) factory.create("김순희");

Car car2 = (Car) factory.create("박철수");

car1.use();

car2.use();

for( int i = 0 ; i < ((CarFactory)factory).getOwners().size() ; i++ ) {

System.out.println(((CarFactory)factory).getOwners().get(i));

}

}

}



[실행 결과]


김순희의 차를 만듭니다.

박철수의 차를 만듭니다.

김순희의 차를 이용합니다.

박철수의 차를 이용합니다.

김순희

박철수





반응형

[Design Pattern] Template Method 패턴



가정에서 요리할 때 필요한 모양틀이 있다. 별모양으로 된 이 틀은 밀가루 반죽을 넣으면 별 모양으로 된 쿠키가 된다. 또한 계란물을 넣으면 별모양 후라이가 되기도 한다.  프로그램을 할 때도 제공된 틀 클래스를 상속 받으면 상속 받은 클래스는 어떠한 것을 구현해도 호출 하는 쪽에서는 수정에 대한 영향도가 없이 다양한 결과를 만들어 낼 수 있다. 이것을 Template Method 패턴이라고 한다.


템플릿 메소드 패턴



가정에서 요리할 때 필요한 틀을 직접 프로그램 해보겠다.

아래 클래스 다이어그램을 보면 AbstractCookShape고정된 요리틀 추상 클래스가 있다. 이것을 상속 받은 CookieShape, EggShape은 틀의 모양을 갖은 쿠키와 계란후라이를 만들어 내는 역할을 한다.


[클래스 다이어그램]



[AbstractCookShape 구현]

재료를 넣고, 요리를 시작, 끝내는 3가지 함수가 있다. 

이 틀에만 맞춰서 구현하면 많은 요리기능을 갖은 클래스를 만들어 낼 수 있다.


public abstract class AbstractCookShape {

public abstract void pourMaterial(String material);

public abstract void startCook();

public abstract void endCook();

}



[CookieShape 구현]

AbstractCookShape을 상속 받아서 쿠키를 요리하는 클래스를 만든다.


public class CookieShape extends AbstractCookShape {

String material = "";

@Override

public void pourMaterial(String material) {

this.material = material;

}


@Override

public void startCook() {

System.out.println("별모양 "+material+"쿠키를 요리 합니다.");

}


@Override

public void endCook() {

System.out.println("별모양 "+material+"쿠키가 완료되었습니다.");

}

}



[EggShape 구현]

AbstractCookShape을 상속 받아서 계란후라이를 요리하는 클래스를 만든다.


public class EggShape extends AbstractCookShape {


String material = "";

@Override

public void pourMaterial(String material) {

this.material = material;

}


@Override

public void startCook() {

System.out.println("별모양 "+material+"후라이를 요리 합니다.");

}


@Override

public void endCook() {

System.out.println("별모양 "+material+"후라이가 완료되었습니다.");

}


}



[Main 구현]

만들어놓은 요리틀을 사용해보자.


public class Main {


public static void main(String[] args) {

AbstractCookShape eggShape = new EggShape();

AbstractCookShape cookieShape = new CookieShape();

eggShape.pourMaterial("계란");

eggShape.startCook();

eggShape.endCook();

cookieShape.pourMaterial("밀가루반죽");

cookieShape.startCook();

cookieShape.endCook();

}

}





반응형

[Design Pattern] Adapter 패턴



한국에서 쓰는 가전 기기를 110V를 쓰는 나라에 가져가면 쓸 수가 없다. 왜냐면 우리나라는 220V로 규격화 되어 있기 때문이다. 110V를 쓰는 나라에서 우리나라 가전기기를 사용하려면 뭐가 필요 할까? 바로 아답터다. 220V 가전기기를 110V에서 사용하기 위해 꼭 필요하다. 프로그램에서도 마찮가지 이다. 이미 구현 되어 있는 Util Class가 존재 한다. 내가 만든 프로그램에서 해당 클래스를 사용하는데 알맞는 인터페이스가 존재 하지 않을 때가 있다. 이때 아덥터 패턴을 사용해 이미 구현된 Class를 사용해 보자.


상속을 사용한 Adapter 패턴



는 내비게이션을 가지고 있다. 이것을 새 차에 장착하고 싶은데 붙일 방법이 없다. 그래서 거치대를 사서 붙였다.

이 상황을 프로그램 해보겠다.


[가전 제품과 예제 비교]

 예제 프로그램

가전 제품 비유

 Car

한국에서 쓰는 가전 제품 

 거치대(Adapter)

아뎁터 (Adapter)

 내비게이션

V110


[클래스 다이어그램]



[전체 예제]

[차에서 내비를 실행]

public class Main {


public static void main(String[] args) {

Car carHasNavi = new Adapter();

carHasNavi.powerOnNavi();

carHasNavi.powerOffNavi();


}

}


===========================================================================================

[차 에서 내비게이션을 동작 하고 싶다.]


public interface Car {

void powerOnNavi();

void powerOffNavi();

}


===========================================================================================

[이미 존재 하는 내비게이션]

public class Navigation {

public void onStart() {

System.out.println("내비게이션 시작");

}

public void onDestory() {

System.out.println("내비게이션 종료");

}

}


===========================================================================================

[거치대는 네비게이션과 차를 상속 받아 결국에 차에서 내비를 실행 할 수 있게 된다.]

public class Adapter extends Navigation implements Car {


@Override

public void powerOnNavi() {

onStart();

}


@Override

public void powerOffNavi() {

onDestory();

}

}



위임을 사용한 Adapter 패턴



앞에서 보여줬던 예제와 비슷하지만 이전에는 상속을 통한 거치대를 구현 했다면 이번엔 위임을 통해 아뎁터 패턴을 알아보겠다.


[클래스 다이어그램]



[파일 쓰는 예제]

[차에서 내비를 실행]

public class Main {


public static void main(String[] args) {

Car carHasNavi = new Adapter();

carHasNavi.powerOnNavi();

carHasNavi.powerOffNavi();


}

}


===========================================================================================

[차 에서 내비게이션을 동작 하고 싶다.]


public abstract class Car {

public abstract void powerOnNavi();

public abstract void powerOffNavi();

}


===========================================================================================

[이미 존재 하는 내비게이션]

public class Navigation {

public void onStart() {

System.out.println("내비게이션 시작");

}

public void onDestory() {

System.out.println("내비게이션 종료");

}

}


===========================================================================================

[거치대는 차를 상속 받아 내부적으로 내비를 생성해 실행하고 있다.]

public class Adapter extends Car {


private Navigation navi = new Navigation();


@Override

public void powerOnNavi() {

navi.onStart();

}


@Override

public void powerOffNavi() {

navi.onDestory();

}

}



반응형

+ Recent posts