C \ # 디자인 모델 의 6 - 원형 모델

일반적인 상황 에서 목표 류 는 원형 중의 데 이 터 를 복제 한 다음 에 자신 이 이용 할 수 있 는 데 이 터 를 개조 하고 이용한다.
목표 류 는 하나 이상 의 원형 류 를 복제 하여 구 조 를 한 다음 에 복 제 된 클래스 의 세부 사항 을 수정 하거나 채 워 서 그 행 위 를 미리 기대 에 부합 하도록 한다.프로 토 타 입 모드 는 일반적으로 부모 데이터 에 대한 클론 문 제 를 설계 합 니 다.
 
일반적인 상황 에서 하나의 클래스 가 하나의 배열 구성원 을 포함 하고 이 클래스 가 ICloneable 인 터 페 이 스 를 실현 한다 면 이 클래스 는 Clone () 방법 으로 복 제 를 할 수 있 지만 복제 가 우리 의 요구 에 부합 되 는 지 는 확실 하지 않다.
 
object Clone();  복제 방법 은 object 류 를 되 돌려 줍 니 다.
 
만약 에 배열 을 포함 하 는 인 스 턴 스 가 복제 된다 면 새로운 인 스 턴 스 의 배열 이 원래 배열 의 인용 일 뿐 이 라면 얕 은 복사 (shallow copy) 라 고 합 니 다. 데이터 대상 의 인용 은 복사 되 었 지만 똑 같은 바닥 데 이 터 를 가리 키 고 있 습 니 다.모든 복사 본 에서 실 행 된 작업 은 원래 인 스 턴 스 의 데 이 터 를 바 꿉 니 다. 어떤 경우 에는 우리 가 원 하 는 결과 가 아 닙 니 다.
그래서 우 리 는 깊이 복사 하여 새로운 데이터 실 체 를 완전히 구축 할 수 있다.
public object Clone() {
			//create a new ArrayList
			ArrayList swd = new ArrayList ();
			//copy in swimmer objects
			for(int i=0; i< swdata.Count ; i++) 
				swd.Add (swdata[i]);
			//create new SwimData object with this array
			SexSwimData newsd = new SexSwimData (swd);
			return newsd;
		}

언제든지 클래스 가 생 성 될 수 있 거나 클래스 가 생 성 된 후에 수 정 될 때 원형 모드 를 사용 할 수 있 습 니 다.모든 종류 가 같은 인터페이스 만 있다 면 그들 은 실제로 상당히 다른 조작 을 할 수 있다.
우 리 는 Swimmer 류 가 하나 있다.
using System;
using CsharpPats;
namespace DeepSexClone
{
	/// <summary>
	/// Summary description for Swimmer.
	/// </summary>
	public class Swimmer:IComparable 	{
		private string name;		 //name
		private string lname, frname;//split names
		private int age;			//age
		private string club;		//club initials
		private float time;			//time achieved
		private bool female;		//sex
	//---------
		public Swimmer(string line) {
			StringTokenizer tok = new StringTokenizer(line,",");
			splitName(tok);
			age = Convert.ToInt32 (tok.nextToken());
			club = tok.nextToken();
			time = Convert.ToSingle (tok.nextToken());
			string sx = tok.nextToken().ToUpper ().Trim ();
			female = sx.Equals ("F");
		}
		//---------
		private void splitName(StringTokenizer tok) {
			name = tok.nextToken();
			int i = name.IndexOf (" ");
			if (i > 0 ) {
				frname = name.Substring (0, i);
				lname = name.Substring (i + 1).Trim ();
			}
		}
		//---------
		public int CompareTo(object swo) {
			Swimmer sw = (Swimmer)swo;
			return lname.CompareTo (sw.getLName() );
		}
		//---------
		public bool isFemale() {
			return female;
		}
		//---------
		public int getAge() {
			return age;
		}
		//---------
		public float getTime() {
			return time;
		}
		//---------
		public string getName() {
			return name;
		}
		//---------
		public string getClub() {
			return club;
		}
		//---------
		public string getLName() {
			return lname;
		}
	}
}

수영 선수 정 보 를 포함 하 는 SwimData 클래스:
using System;
using System.Collections ;
using CsharpPats;

namespace DeepSexClone
{
	/// <summary>
	/// Summary description for SwimData.
	/// </summary>
	public class SwimData:ICloneable 	{
		protected ArrayList swdata;
		private int index;
		//-----
		public SwimData() {
				swdata = new ArrayList ();
		}
		//-----
		public SwimData(ArrayList swd) {
			swdata = swd;
			index=0;
		}
		//-----
		public int count() {
			return swdata.Count ;
		}
		//-----
		public SwimData(string filename) 		{
			swdata = new ArrayList ();
			csFile fl = new csFile(filename);
			fl.OpenForRead ();
			string s = fl.readLine ();
			while(s != null) {
				Swimmer sw = new Swimmer(s);
				swdata.Add (sw);
				s = fl.readLine ();
			}
			fl.close ();
		}
		//-----
		public object Clone() {
			//create a new ArrayList
			ArrayList swd = new ArrayList ();
			//copy in swimmer objects
			for(int i=0; i< swdata.Count ; i++) 
				swd.Add (swdata[i]);
			//create new SwimData object with this array
			SwimData newsd = new SwimData (swd);
			return newsd;
		}
		//-----
		public void moveFirst() {
			index = 0;
		}
		//-----
		public bool hasMoreElements() {
			return (index < swdata.Count-1 );
		}
		//-----
		public void sort() {
		//sort using IComparable interface of Swimmer
			swdata.Sort (0, swdata.Count , null);
		}
		//-----
		public Swimmer getSwimmer() {
			if(index < swdata.Count )
				return (Swimmer)swdata[index++];
			else
				return null;
		}
	}
}

우 리 는 SwimData 류 를 계승 하 는 부류 가 있 는데, 이러한 SwimData 류 를 계승 하 는 자 류 는 부류 중의 수영 선수 들 의 정 보 를 복제 해 야 한다.저 희 는 SexsumData 류 가 SwimData 류 를 계승 하고 이런 유형 은 수영 선수 에 대한 정렬 방법 이 있 습 니 다. 그리고 SexsumData 류 는 자신의 Clone () 방법 이 필요 합 니 다. 서로 다른 데이터 형식 으로 돌아 가 야 하기 때문에 이런 유형 에서 부모 류 의 Clone () 방법 을 다시 써 야 합 니 다.
public object Clone() {
			//create a new ArrayList
			ArrayList swd = new ArrayList ();
			//copy in swimmer objects
			for(int i=0; i< swdata.Count ; i++) 
				swd.Add (swdata[i]);
			//create new SwimData object with this array
			SexSwimData newsd = new SexSwimData (swd);
			return newsd;
		}

이렇게 해서 매번 새로운 SwimData 클래스 의 하위 클래스 가 실 현 될 때마다 부모 클래스 의 Clone () 방법 을 다시 써 야 한다. 돌아 올 데이터 가 다 르 기 때문에 이것 은 매우 좋 지 않 은 방법 이다.더 좋 은 실현 방안 은 Clone () 방법 이 있 는 모든 클래스 에서 ICloneable 인터페이스의 제한 을 취소 하고 반전 처리 과정 을 통 해 모든 수신 류 가 전송 류 내부 의 데 이 터 를 복제 하 는 것 이다.
 
이렇게 해서 SwimData 류 의 변경 은 다음 과 같다.
public virtual void cloneMe(SwimData swdat) {
			swdata = new ArrayList ();
			ArrayList swd=swdat.getData ();
			//copy in swimmer objects
			for(int i=0; i < swd.Count ; i++) 
				swdata.Add (swd[i]);
		
		}

 
Clone () 함 수 를 취소 하고 ICloneable 인터페이스 에 대한 실현 을 취소 하 며 위의 함수 cloneMe () 를 사용 합 니 다.
이 방법 은 SwimData 의 모든 하위 클래스 에 사용 할 수 있 습 니 다. 하위 클래스 간 에 데이터 의 강제 형식 전환 이 필요 하지 않 기 때 문 입 니 다.모든 하위 클래스 는 같은 데 이 터 를 가지 고 있다.
 
예 를 들 어 수영 선수 정보 에 따라 나이 분포 주 상 도 를 그 려 보 자.
AgeSwimData 클래스 는 SwimData 클래스 에서 계 승 됩 니 다.
using System;
using System.Collections ;
namespace DeepSexClone
{
	/// <summary>
	/// Summary description for SexSwimData.
	/// </summary>
	public class AgeSwimData:SwimData
	{
		ArrayList swd;
		public AgeSwimData() {
			swdata = new ArrayList ();
		}
		//------
		public AgeSwimData(string filename):base(filename){}
		public AgeSwimData(ArrayList ssd):base(ssd){}
		//------
		public override void cloneMe(SwimData swdat) {
			swd = swdat.getData ();
		}
		//------
		public override void sort() {
			Swimmer[] sws = new Swimmer[swd.Count ];
			//copy in swimmer objects
			for(int i=0; i < swd.Count ; i++) {
				sws[i] = (Swimmer)swd[i];
			}
            //sort into increasing order
			for( int i=0; i< sws.Length ; i++) {
				for (int j = i; j< sws.Length ; j++) {
					if (sws[i].getAge ()>sws[j].getAge ()) {
						Swimmer sw = sws[i];
						sws[i]=sws[j];
						sws[j]=sw;
					}
				}
			}
			int age = sws[0].getAge ();
			int agecount = 0;
			 int k = 0;
			swdata = new ArrayList ();
			bool quit = false;
			
			while( k < sws.Length && ! quit ) {
				while(sws[k].getAge() ==age && ! quit) {
					agecount++;
					if(k < sws.Length -1)
						k++;
					else
						quit= true;
				}
				//create a new Swimmer with a series of X's for a name
				//for each new age
				string name = "";
				for(int j = 0; j < agecount; j++)
					name +="X";
				Swimmer sw = new Swimmer(age.ToString() + " " +
					name + "," + age.ToString() + ",club,0,F");
				swdata.Add (sw);
				agecount = 0;
				if(quit)
					age = 0;
				else
					age = sws[k].getAge ();
			}
		
		}
	}
}

AgeSwimData 의 cloneMe () 방법 은 들 어 오 는 데이터 에 대한 인용 형식 을 되 돌려 주 고 깊이 복사 하지 않 았 습 니 다.그러나 sort 방법 에 서 는 한 선수 의 정 보 를 저장 하 는 새로운 복사 본 을 만 들 고 이 선수 의 배열 을 정렬 하여 데 이 터 를 변경 하지 않 았 습 니 다.
private void btClone_Click(object sender, System.EventArgs e) {
			AgeSwimData newSd = new AgeSwimData ();		
			newSd.cloneMe (swdata);
			newSd.sort ();
			lsNewKids.Items.Clear() ;
			while(newSd.hasMoreElements() ) {
				Swimmer sw = (Swimmer)newSd.getSwimmer ();
				lsNewKids.Items.Add (sw.getName() );
			}
		}

 
이렇게 메 인 프로그램 에 AgeSwimData 의 인 스 턴 스 를 새로 만 들 었 습 니 다. 이 인 스 턴 스 는 정렬 할 때 원래 들 어 온 인 스 턴 스 데이터 가 아 닙 니 다.
 
프로 토 타 입 모델 의 가장 큰 장점 은 어떤 하위 클래스 로 돌아 가 든 이 종 류 를 새로운 유형 으로 바 꾸 지 않 아 도 프로그램 에서 사용 할 수 있다 는 것 이다. 부모 등급 의 추상 류 나 기본 적 인 방법 은 충분히 사용 해 야 한다. 클 라 이언 트 는 현재 처리 하고 있 는 것 이 진정한 하위 클래스 의 어떤 종류 인지 알 필요 가 없다.
새로운 인 스 턴 스 를 만 드 는 데 더 많은 대가 가 필요 할 때 프로 토 타 입 모드 는 새로운 인 스 턴 스 를 만 드 는 것 이 아니 라 기 존 클래스 를 복사 하거나 복제 합 니 다.

좋은 웹페이지 즐겨찾기