1. Class 초기화에 사용하는 일반적인 방법


1-1. Class 예시:

package init.pattern.example;

public class Person {
	private String name = "CHAE";
	private String id = "4600";
	private int age = 20;
	private int weight = 100;
	private int height = 180;
	private String phone = "02-1234-5678";

	public Person()
	{}
	
	public Person(String name,  String id, int age, int weight, int height, String phone) {
		this.name = name;
		this.id = id;
		this.age = age;
		this.weight = weight;
		this.height = height;
		this.phone = phone;
	}
	
	public void print()
	{
		System.out.println("NAME: "+ name + " ID: "+ id);
		System.out.println("AGE: " + age + " WEIGHT: "+ weight + " HEIGHT: " + height + " PHONE: " + phone);
	}
	
	public void name(String name) {
		this.name = name;
	}
	
	public void id(String id) {
		this.id = id;
	}
	
	public void age(int age) {
		this.age = age;
	}
	
	public void weight(int weight) {
		this.weight = weight;
	}
	
	public void height(int height) {
		this.height = height;
	}
	
	public void phone(String phone) {
		this.phone = phone;
	}
	

}

   

1-2. 사용 예시:

package init.pattern.example;

public class MainCommon {

	public static void main(String[] args) {
		
		Person p1 = new Person("CHAE", "1500", 50, 60, 150, "02-1111-2222");
		p1.print();
		
		Person p2 = new Person();
		p2.name("KIM");
		p2.id("3200");
		p2.age(40);
		p2.print();
	}

}

 

 

 

1-3. 출력 예시:

NAME: CHAE ID: 1500
AGE: 50 WEIGHT: 60 HEIGHT: 150 PHONE: 02-1111-2222
NAME: KIM ID: 3200
AGE: 40 WEIGHT: 100 HEIGHT: 180 PHONE: 02-1234-5678

 

1-4. 불편한 점:

- 초기화 변수가 많아질 수록 코드가 길어짐.

- 필수 초기화 변수와 선택적 초기화 변수 구분 가독성이 떨어짐.

 

 

 

 


2. Class 초기화 변수가 많은 경우 유용한 Builder 패턴


2-1. Class 예시:

package builder.pattern.example;

public class Person {
	private final String name;
	private final String id;
	private final int age;
	private final int weight;
	private final int height;
	private final String phone;
	
	private Person(Builder builder) {
		name = builder.name;
		id = builder.id;
		age = builder.age;
		weight = builder.weight;
		height = builder.height;
		phone = builder.phone;
		
	}
	
	public void print()
	{
		System.out.println("NAME: "+ name + " ID: "+ id);
		System.out.println("AGE: " + age + " WEIGHT: "+ weight + " HEIGHT: " + height + " PHONE: " + phone);
	}
	
	public static class Builder{
		//essential param.
		private final String name;
		private final String id;
		
		//optional param.
		private int age = 50;
		private int weight = 100;
		private int height = 175;
		private String phone = "02-1234-5678";
		
		
		
		public Builder(String name, String id){
			this.name = name;
			this.id = id;
		}
		
		public Builder age(int val){
			age = val;
			return this;
		}
		
		public Builder weight(int val){
			weight = val;
			return this;
		}
		
		public Builder height(int val){
			height = val;
			return this;
		}
		
		public Builder phone(String val){
			phone = val;
			return this;
		}
		
		public Person build(){
			return new Person(this);
		}
		
	}
	


}

 

2-2. 사용 예시:

package builder.pattern.example;

public class MainBuilder {

	public static void main(String[] args) {

		Person p1 = new Person.Builder("CHAE", "8900").age(30).weight(80).height(190).phone("02-1111-2222").build();
		p1.print();
		
		Person p2 = new Person.Builder("KIM", "1200").age(28).build();
		p2.print();
		
		

	}

}

 

2-3. 출력 예시:

NAME: CHAE ID: 8900
AGE: 30 WEIGHT: 80 HEIGHT: 190 PHONE: 02-1111-2222
NAME: KIM ID: 1200
AGE: 28 WEIGHT: 100 HEIGHT: 175 PHONE: 02-1234-5678

 

2-4. 개인 의견:

- Class 초기화 변수가 많거나 늘어날 것 같은 경우, 유용한 패턴이 될 것 같음.

- Class 초기화 변수가 적은 경우, 불필요할 것 같음(오히려 구현하는 시간이 아까울 것 같음) 

 

 

# CODE: https://gitlab.com/YuJungChae/design_pattern/tree/builder_pattern

Posted by miniature88
,

앞에 포스팅한 추상 클래스와 이어지는 내용이다.

 

c++은 다중 상속언어로 언어적으로 인터페이스를 지원하지는 않는다.

단, 자바는 추상클래스의 경우는 abstract 키워드, 인터페이스의 경우는 interface 키워드를 사용한다.

 

그렇다면 C++ 사용 시, 인터페이스와 추상 클래스의 차이는 없는 걸까?

그렇지 않다. 모호하지만 엄격하게 설명하자면 다음과 같다.

 

추상 클래스는 '생성자, 멤버 변수, 일반 메소드'를 자유롭게 포함할 수 있으며, 여기에 1개 이상의 추상 메소드가 포함되어져 있으면 된다.

 

그러나,  인터페이스는 '추상 메소드'만으로 이루어져 있다.

 

예제 코드로 비교해보자. (c++)

 

[추상 클래스 예제]

 

 

 

[인터페이스 예제]

 

 

Posted by miniature88
,

# 가상 함수(Virtual Method)

껍데기만 선언하고, 알맹이! 구현은 하위 클래스에 맡기는 것!

다형성을 위한 것!

 

# 추상 클래스(Virtual Class)

가상 함수(순수 가상 함수)를 하나 이상 포함하고 있는 클래스!

인스턴스 생성 불가!

 

# 가상 함수 및 추상 클래스 사용 예제 [c++] 

[깨알같은 상황극] 

서점을 운영하는데, 도매로 책을 사와서 소매로 책을 판매한다.

그런데, 사장은 직원에게 책 분류 명령을 내려야하는데!

책 종류에 따라 분류 되어져야하는 특성상 소설책으로 분류해! 에세이로 분류해! 번거롭게 명령내려야하면 사장은 눈물남ㅠㅠ 무엇보다, 판타지, 잡지, 시, 만화 등...책 종류가 늘어날 수록 사장은 번거로워진다.

이런 상황을 방지할 수 있는것이 추상 클래스를 이용하는 것 이다. (인터페이스 개념 및 비교는 다음 포스팅에!) 사장은 그저 책을 분류하라는 명령만 내리면 되는 것이다!

 

[코드 설명] 

책이라는 추상 클래스를 상속받은 소설 클래스와 에세이 클래스!

분류()라는 가상 메소드를 에세이 클래스와 소설 클래스에서 각각 다르게 구현!

 

[실행 결과]

 

  

 

 

# 가상 함수 및 추상클래스 사용하지 않은 경우

[설명]

책 종류가 늘어나면 상당히 번거로워진다. ㅠㅠ

 

 

# 궁금한 것 !

- 가상 소멸자를 이용한 이유!

: 가상 소멸자를용하는 것은 의무는 아니지만, 소멸자 사용을 원한다면! 가상 함수를 이용하는 경우에는 소멸자도 가상이어야 한다. 파생된 객체에 대한 포인터가 삭제되는 경우 문제가 발생 할 수 있기 때문이다. 문제의 상황은 다음과 같다.

 

 

 

 

 

 

추상클래스의 소멸자만 호출되는 상황 발생! 흐름상 말도안된다ㅠ_ㅠ 따라서, 클래스에 가상 함수가 있다면 소멸자도 가상이어야 한다!

 

-추상클래스의 인스턴스를 생성할 수도 있을까?

 

 

 처음에 설명했던대로, 추상 클래스의 인스턴스는 생성할 수 없다!

 

-추상 클래스의 가상 함수는 두 개인데, 파생된 클래스에서 그중에 일부를 재정의 하지 않는 경우는 어떻게 될까?

 

결과는 다음과 같다.

 

 

에러가 발생하게 되는데, 애초에 추상 메소드를 정의하여, 추상 클래스를 만드는 것은 해당 메소드를 하위단에서 재정의 해주는 것을 원하기 때문에 당연한 결과라고 할 수 있다. 즉, 개발자 A가 만든 추상 클래스를 사용하는 개발자 B가 실수로 일부를 재정의 하지 않는 경우는 에러가 하므로 개발자A의 의도가 전달된다고 할 수 있다.

 

-추상 클래스의  멤버 함수를 가상(Virtual)으로 만들었으면, 파생 클래스에서도 가상으로 선언해서 구현해야하는가?

아니다 굳이 virtual을 붙여주지 않아도 내부적으로는 자동으로 가상 함수로 처리된다. 그러나 코드를 이해하기 쉽게, 알아보기 쉽게 붙여주는 것이 좋을 것 같다.

Posted by miniature88
,

[ppt 첨부Observer.pptx

 

 

◈ Observer Pattern 정의

특정 데이터를 감시하고 있다가 변화 발생시,

시스템에 이를 알리고 연관된 객체들이 적절한 작

동일한 인터페이스를 이용하여 실행하도록 만들어주는 패턴.

 

객체1의 상태가 변하면 연관 객체 2,3,4에 사항을 알리고 자동적으로 수정!

 

 

 

이벤트 처리를 연상시킨다 !

 

◈ Observer Pattern 필요 이유

한 객체에 가해진 변경으로 다른 객체를 변경해야 하는 경우.

변경 되어져야 하는 객체수가 많은 경우! 번거로워지기 때문에.

옵저버 패턴을 이용하면 추후에 발생하는 불편함을 줄일 수 있다. 

 

 ◈ Observer Pattern 예제(C++)

 

성적 값이 변한경우, 성적값을 표시하는 표와 그래프 값이 변하게 되는데.

성적 값이 변할때마다 따로 처리해주면 번거롭지만 옵저버 패턴을 이용하면

보다 편하게 변한 성적 값에 따라 표와 그래프에 변경된 값을 반영할 수 있다.

 

[소스 코드 첨부]

main.cpp

 

#include <iostream>
#include <vector>
using namespace std;

class Observer{
public:
 virtual void Update(int 언어, int 수학, int 외국어)=0;
};

class Subject{
public:
 virtual void NotifyObserver()=0;
 virtual void AddObserver(Observer* input)=0;
};

class 성적Data : public Subject{
public:
 virtual void NotifyObserver(){
  for (unsigned int i=0; i<observerList.size();i++)
  {
   observerList[i]->Update(m_언어,m_수학,m_외국어);
  }
 }

 virtual void AddObserver(Observer* input){
  observerList.push_back(input);
 }

 void setData(int 언어, int 수학, int 외국어){
  m_언어=언어;
  m_수학=수학;
  m_외국어=외국어;
 }

private:
 vector<Observer*> observerList;

 int m_언어;
 int m_수학;
 int m_외국어;
};


class : public Observer{
public:
 virtual void Update(int 언어, int 수학, int 외국어){
  m_언어=언어;
  m_수학=수학;
  m_외국어=외국어;

  Print();
 }

private:
 void Print(){
  cout<<"언어: "<<m_언어<<endl;
  cout<<"수학: "<<m_수학<<endl;
  cout<<"외국어: "<<m_외국어<<endl;
 }

private:
 int m_언어;
 int m_수학;
 int m_외국어;
};

class 그래프 : public Observer{
public:
 virtual void Update(int 언어, int 수학, int 외국어){
  m_언어=언어;
  m_수학=수학;
  m_외국어=외국어;

  Print();
 }

private:
 void Print(){

  for (unsigned int i=0; i<m_언어;i++)
  {
   if (i==0)
   {
    cout<<"언어   ";
   }
   cout<<"□";

  }

  cout<<endl;

  for (int i=0; i<m_수학;i++)
  {
   if (i==0)
   {
    cout<<"수학   ";
   }
   cout<<"□";
  }

  cout<<endl;

  for (int i=0; i<m_외국어;i++)
  {
   if (i==0)
   {
    cout<<"외국어 ";
   }
   cout<<"□";
  }
  cout<<endl;
  
 }

private:
 int m_언어;
 int m_수학;
 int m_외국어;
};

void main(){

 성적Data* 성적=new 성적Data;
 표* 성적표=new 표;
 그래프* 성적그래프=new 그래프;
 
 cout<<"[갱신 1]"<<endl;
 성적->AddObserver(성적표);
 성적->setData(6,2,3);
 성적->NotifyObserver();

 

 cout<<"\n[갱신 2]"<<endl;
 성적->AddObserver(성적그래프);
 성적->setData(10,12,7);
 성적->NotifyObserver();
}

 

 

 

 

Posted by miniature88
,

◈ Iteratro Pattern 정의

복합 객체 요소들의 내부 표현 방식은 공개하지 않고,

순차적인 접근 방법을 제공하는 패턴.

 

◈ Iteratro Pattern 구현 방법

객체 집단을 특정객체(iterator)에 넣고, 동일한 방법으로 객체 집단 속 객체가

다뤄질 수 있도록 만들어 준다.

 

◈ Iteratro Pattern 예제(c++)

자판기에 음료를 추가하는 시나리오.

이터레이터 패턴을 이용해, 추가된 음료수에 보다 간편하게 접근.

[소스코드 첨부]

main.cpp

 

 

 

 

 

 

 

 

 

 

 

Posted by miniature88
,

◈ Command Pattern 사전적 의미
- 명령
- 명령어

 

◈ Command Pattern 정의

서로 다른 요청을 객체화하여 클라이언트에게 파라미터로 넘겨줄 수 있도록 하는 패턴

◈ 이런 상황이 있다고 가정해보자

 

 

동물원 관장(클라이언트)이 동물원 관리를 하려고 하는데, 직원한테 흑염소, 당나귀, 코끼리 우리 청소 좀 하고 흑염소, 당나귀, 코끼리 밥좀 챙겨줘 라고 세부적인 지시를 내린다면 관장님은 매번 피곤할 것이다. 동물 종류가 늘어나면... 관장님은 쌍코피 터짐.....

동물원 관장은 내부적인! 세부적인! 내용을 알필요 없이 그저 직원에게 명령을 내리면 된다. "동물 우리 청소하고!! 밥 좀 챙겨줘!" 라고 말이다.

 

◈ Command Pattern 패턴을 사용하지 않은 경우

 

관장님(사용자)가 원하는 작업을 수행하기 위해 내부적인 부분까지 모두 알고 있어야하고, 매번 번거롭게 하나하나 명령 내려줘야하기 때문에 번거롭다!

 

◈ Command Pattern 패턴을 사용한 경우

[C++로 만들어 본 예제 소스 코드 ]

[소스코드 파일 첨부함]

main.cpp

 

관장님(사용자)을 직원을 통해 명령을 내리게 되는데, 원하는 각각의 명령을 인자값으로 명령만 해주면 되기 때문에 편리하다. 무엇보다 관장님 입장에서는 그저- 원하는 명령만 내려주면 되는 것! 즉, 내부적인 부분에 대해서 몰라도 되기 때문에 유용한 패턴이다.  

 

Posted by miniature88
,
Composite 사전적 의미 

- 합성의

- 합성물 

 

   Composite Pattern이란?

클라이언트가 사용할 개별 객체와 복합 객체를 코드상에서 따로

구분하지 않고 이들의 공통점으로 만들어진 인터페이스를 구성해,  모두 동일하게 다룰 수 있도록 한다.

 

◈ Composite Pattern 사용하지 않는 경우

 

 

사장(클라이언트 입장)이 직원 네 명에게 명령을 내리고 싶을 때,

'번거롭게' 직원 네 명에게 명령을 네 번 내려줘야하는 불편함이

발생한다. 무엇보다 직원 수가 늘어나는 경우! 사장은 일일이 명령을 내려줘야하기때문에 점점 더 불편해지는 상황이 발생한다.

 

◈ Composite Pattern 사용한 경우

 

 

과장을 한명 고용해, 사장이 과장을 통해 한 번만 명령을 내리면 과장이 알아서 직원 네명에게 명령을 전달함으로써 사장(클라이언트)은 보다 편리하게 직원들에게 명령을 내릴 수 있게 된다.

 

◈ Composite Pattern 예제 (C++)

과장이 직원들을 리스트에 담아 내부적으로 처리해, 사장이 한 번만 명령을 내려도 등록된 모든 직원들에게 명령이 전달될 수 있도록 컴포지트

패턴 예제 소스를 작성한 것 이다.

[파일 첨부 함]   example.cpp   

       #include <list>
#include <iostream>

class ReportSender
{
public:
    virtual void sendReport() = 0;
};

class 과장Composite : public ReportSender
{
public:
    void sendReport()
    {
        std::list<ReportSender*>::iterator itor;

               //과장이 내부적으로 for문을 돌려 직원들에게 명령을 내림
        for(itor = senderList.begin(); itor != senderList.end(); ++itor) 
        {
            (*itor)->sendReport();
        }
    }
    void addSenderList(ReportSender* sender)
    {
        senderList.push_back(sender);
    }

private:
   std::list<ReportSender*> senderList;  //직원들을 저장할 리스트   
};

 

//모든 직원들을 동일한 방법으로 명령을 내릴 수 있도록 ReportSender 인터페이스를 상속받아 구현!

class 직원1 : public ReportSender
{
public:
    void sendReport()
    {
        std::cout<<"직원1"<<std::endl;
    }
   
};

class 직원2 : public ReportSender
{

    void sendReport()
    {
        std::cout<<"직원2"<<std::endl;
    }

};

class 직원3 : public ReportSender
{

    void sendReport()
    {
        std::cout<<"직원3"<<std::endl;
    }

};

void main()
{
    과장Composite* compositeReportSender = new 과장Composite;

           compositeReportSender->addSenderList(new 직원3);
    compositeReportSender->addSenderList(new 직원1);
    compositeReportSender->addSenderList(new 직원2);

           compositeReportSender->sendReport();

           //등록된 모든 직원들에게 재차 명령을 내리고 싶을때

         //compositeReportSender->sendReport()를 한 번만 다시 호출하면 되니까 편하다!
}

       
   

 

 

 

 

Posted by miniature88
,