| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | «  : 10-10-2008 19:59 »  |  | 
 
 Допустим, должен иметься жёстко заданный и неизменный во время эксплуатации программы иерархический классификатор типа:
 (B(A(C, B), P(L, C, R, P, M, W, T)), O(I(D), C(N, O)))
 
 Соответственно, имеем допустимые классификационные коды:
 
 BAC, BAB, BPL, BPC, BPR, BPP, BPM, BPW, BPT, OID, OCN, OCO.
 
 Если буквы в программе заменить на осмысленные названия, то получим набор enum-ов.
 
 Спрашивается, как написать такой(ие) класс(ы) в программе (а точнее, какой у него(них) должен быть интерфейс), чтобы он(и):
 1) описывал(и) значение классификатора;
 2) позволял(и) бы пользователю читать отдельные позиции классификационного кода (поскольку они имеют самостоятельный смысл);
 3) позволял(и) бы конструировать классификационный код в рамках допустимых классификатором возможностей - записывать отдельные позиции классификационного кода.
 
 Можно, конечно, по позициям классификационного кода завести 3 enum-а:
 1) B, O
 2) A, P, I, C
 3) C, B, L, C (2-й раз повторяется, можно убрать), R, P, M, W, T, D, N, O
 и дальше на уровне логики записи блокировать присваивание недопустимых для 1 и 2-го уровней значений 3-го уровня и т.д.
 
 Но можно ли изящнее решить задачу?
 
 P.S. Прошу предлагать решения для языков программирования со строгой типизацией. Понятно, что в языках без строгой типизации можно менять интерфейс объекта во время исполнения.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Finch 
								СпокойныйАдминистратор    Offline 
								Пол:    
								Пролетал мимо
								
								
								
								
								
							 | 
								|  | « Ответ #1 :  10-10-2008 20:06 »   |  | 
 
 dimka, А можно более наглядно и на пальцах объяснить? На примере. Что то в абстракции у меня туго. Не могу понять задачу. |  
						| 
								|  |  
								|  |  Записан | 
 
 Не будите спашяго дракона.              Джаффар (Коша) |  |  | 
	| 
			| 
					
						| Finch 
								СпокойныйАдминистратор    Offline 
								Пол:    
								Пролетал мимо
								
								
								
								
								
							 | 
								|  | « Ответ #2 : 10-10-2008 20:23 »  |  | 
 
 Из того, что я понял. Класс в принципе может быть один. Но он должен сам уметь выстраивать иеархические деревья. Теперь задача другая. Например B это просто буква, или это может быть и слово? |  
						| 
								|  |  
								|  |  Записан | 
 
 Не будите спашяго дракона.              Джаффар (Коша) |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #3 : 10-10-2008 21:39 »  |  | 
 
 Например B это просто буква, или это может быть и слово? Например, значение enum-а. При этом тип enum-а желательно сохранить. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Finch 
								СпокойныйАдминистратор    Offline 
								Пол:    
								Пролетал мимо
								
								
								
								
								
							 | 
								|  | « Ответ #4 : 10-10-2008 21:48 »  |  | 
 
 На стадии компиляции это шаблоны. Но я так понял, тебе уже нужно на стадии работы программы? |  
						| 
								|  |  
								|  |  Записан | 
 
 Не будите спашяго дракона.              Джаффар (Коша) |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #5 : 10-10-2008 21:55 »  |  | 
 
 Finch, да. Видимо, нужно решение в духе объявления типов Variant. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Finch 
								СпокойныйАдминистратор    Offline 
								Пол:    
								Пролетал мимо
								
								
								
								
								
							 | 
								|  | « Ответ #6 : 10-10-2008 21:59 »  |  | 
 
 Тут LogRus как-то в Эврике свой пример с enum давал. Можно сделать абстрактный базовый enum класс, и от него уже плодить потомков. Твоя Иеархия будет работать как с абстрактным классом, Но подставлять ты будеш потомков.
 Теперь встает вопрос один. Как сделать так, чтобы класс знал, какие и сколько членов в enum. Ясно, что он будет работать как с числами. Но все равно, можно задать константы в разнобой.
 |  
						| 
								|  |  
								| « Последнее редактирование: 10-10-2008 22:04 от Finch » |  Записан | 
 
 Не будите спашяго дракона.              Джаффар (Коша) |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #7 : 11-10-2008 08:36 »  |  | 
 
 Тут LogRus как-то в Эврике свой пример с enum давал. Можно сделать абстрактный базовый enum класс, и от него уже плодить потомков. Твоя Иеархия будет работать как с абстрактным классом, Но подставлять ты будеш потомков. Ни в коем случае. Будет в духе: class MyEnum{
 public:
 enum Enum
 {
 A, B
 };
 private:
 Enum value;
 public:
 MyEnum(Enum value);
 Enum getValue() const;
 void setValue(Enum value);
 };
 Такой класс имеет методы, типы результатов и аргументов которого привязаны к конкретному enum-у. Если мы вынесем enum в шаблонный параметр класса - ничего по сути не изменится, поскольку MyEnum<EnumA> и MyEnum<EnumB> - это разные типы с разными интерфейсами, и они не сводимы к общему классу с единым интерфейсом. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #8 : 11-10-2008 12:49 »  |  | 
 
 Если писать на языке со строгой типизацией без применения параметризации классов, а также без RTTI и всяких хакерских приёмов, то получится примерно так: Модуль классификатора: { Прототип реализации иерархического классификатора вида (A(C D) B(E F)). }unit Classifier;
 
 interface
 
 type
 EnumType = (A, B);
 EnumAType = (C, D);
 EnumBType = (E, F);
 
 { Любой уровень классификатор может как иметь, так и не иметь некоторое
 значение. Любой уровень кроме последнего имеет ссылку на следующий
 уровень. Любой уровень кроме первого имеет ссылку на предыдущий уровень.
 Следующий уровень может быть произвольным для текущего. Предыдущий уровень
 должен быть конкретным для текущего.
 
 Пользователь может попытаться прочитать значение уровня и получит в
 результате: либо признак успешного выполнения операции и прочитанное
 значение, если какое-то значение хранится в уровне, и пользователь запросил
 значение типа, соответствующего типу хранящегося в уровне значения;
 либо признак неудачного выполнения операции, если в уровне не хранится
 никакого значения, или тип запрашиваемого значения не соответствует типу
 хранящегося значения.
 
 Пользователь может попытаться установить значение уровня -
 устанавливаемое значение будет проверено на соответствие типам ранее
 установленных значений в предыдущем и следующем уровнях. Если такое
 соответствие будет обнаружено, значение будет сохранено, и пользователь
 получит признак успешного выполнения операции, в противном случае он
 получит признак неудачного выполнения операции. }
 
 ClassifierLevelPointerType = ^ClassifierLevelType;
 ClassifierLevelType =
 object
 private
 HasValue: Boolean;
 NextLevelPointer: ClassifierLevelPointerType;
 constructor Create;
 procedure SetNextLevel(ANextLevel: ClassifierLevelPointerType);
 function Verify: Boolean; virtual;
 function NextConformsToCurrent: Boolean;
 public
 procedure Clear;
 function IsEmpty: Boolean;
 end;
 
 ClassifierLevel1PointerType = ^ClassifierLevel1Type;
 ClassifierLevel1Type =
 object(ClassifierLevelType)
 private
 Value: EnumType;
 public
 constructor Create;
 function SetValue(AValue: EnumType): Boolean;
 function GetValue(var AValue: EnumType): Boolean;
 end;
 
 ClassifierLevel2PointerType = ^ClassifierLevel2Type;
 ClassifierLevel2Type =
 object(ClassifierLevelType)
 private
 PreviousLevelPointer: ClassifierLevel1PointerType;
 ValueIn: Pointer;
 ValueA: EnumAType;
 ValueB: EnumBType;
 function Verify: Boolean; virtual;
 function PreviousConformsToCurrent(TestPreviousValue: EnumType): Boolean;
 public
 constructor Create(APreviousLevelPointer: ClassifierLevel1PointerType);
 function SetValueA(AValue: EnumAType): Boolean;
 function SetValueB(AValue: EnumBType): Boolean;
 function GetValueA(var AValue: EnumAType): Boolean;
 function GetValueB(var AValue: EnumBType): Boolean;
 end;
 
 ClassifierType =
 object
 private
 Level1: ClassifierLevel1Type;
 Level2: ClassifierLevel2Type;
 public
 constructor Create;
 function GetLevel1Pointer: ClassifierLevel1PointerType;
 function GetLevel2Pointer: ClassifierLevel2PointerType;
 end;
 
 implementation
 
 constructor ClassifierLevelType.Create;
 begin
 HasValue := False;
 NextLevelPointer := nil;
 end;
 
 procedure ClassifierLevelType.SetNextLevel;
 begin
 NextLevelPointer := ANextLevel;
 end;
 
 function ClassifierLevelType.Verify;
 begin
 Verify := True;
 end;
 
 function ClassifierLevelType.NextConformsToCurrent: Boolean;
 begin
 if NextLevelPointer <> nil then
 NextConformsToCurrent := NextLevelPointer^.Verify
 else
 NextConformsToCurrent := True;
 end;
 
 procedure ClassifierLevelType.Clear;
 begin
 HasValue := False;
 end;
 
 function ClassifierLevelType.IsEmpty;
 begin
 IsEmpty := not HasValue;
 end;
 
 constructor ClassifierLevel1Type.Create;
 begin
 inherited Create;
 end;
 
 function ClassifierLevel1Type.SetValue;
 var
 OldHasValue: Boolean;
 OldValue: EnumType;
 begin
 OldValue := Value;
 OldHasValue := HasValue;
 Value := AValue;
 HasValue := True;
 if not NextConformsToCurrent then
 begin
 SetValue := False;
 Value := OldValue;
 HasValue := OldHasValue;
 end
 else
 SetValue := True;
 end;
 
 function ClassifierLevel1Type.GetValue;
 begin
 if HasValue then
 begin
 AValue := Value;
 GetValue := True;
 end
 else
 GetValue := False;
 end;
 
 function ClassifierLevel2Type.PreviousConformsToCurrent;
 var
 PreviousValue: EnumType;
 begin
 if PreviousLevelPointer^.GetValue(PreviousValue) then
 PreviousConformsToCurrent := PreviousValue = TestPreviousValue
 else
 PreviousConformsToCurrent := True;
 end;
 
 constructor ClassifierLevel2Type.Create;
 begin
 inherited Create;
 if APreviousLevelPointer = nil then
 Fail;
 PreviousLevelPointer := APreviousLevelPointer;
 ValueIn := nil;
 end;
 
 function ClassifierLevel2Type.Verify;
 begin
 if not HasValue then
 Verify := True
 else if (ValueIn = @ValueA) and PreviousConformsToCurrent(A) then
 Verify := True
 else if (ValueIn = @ValueB) and PreviousConformsToCurrent(B) then
 Verify := True
 else
 Verify := False
 end;
 
 function ClassifierLevel2Type.SetValueA;
 var
 OldHasValue: Boolean;
 OldValueA: EnumAType;
 OldValueB: EnumBType;
 OldValueIn: Pointer;
 begin
 OldValueA := ValueA;
 OldValueB := ValueB;
 OldValueIn := ValueIn;
 OldHasValue := HasValue;
 ValueA := AValue;
 HasValue := True;
 ValueIn := @ValueA;
 if not PreviousConformsToCurrent(A) or not NextConformsToCurrent then
 begin
 SetValueA := False;
 ValueA := OldValueA;
 ValueB := OldValueB;
 ValueIn := OldValueIn;
 HasValue := OldHasValue;
 end
 else
 SetValueA := True;
 end;
 
 function ClassifierLevel2Type.SetValueB;
 var
 OldHasValue: Boolean;
 OldValueA: EnumAType;
 OldValueB: EnumBType;
 OldValueIn: Pointer;
 begin
 OldValueA := ValueA;
 OldValueB := ValueB;
 OldValueIn := ValueIn;
 OldHasValue := HasValue;
 ValueB := AValue;
 HasValue := True;
 ValueIn := @ValueB;
 if not PreviousConformsToCurrent(B) or not NextConformsToCurrent then
 begin
 SetValueB := False;
 ValueA := OldValueA;
 ValueB := OldValueB;
 ValueIn := OldValueIn;
 HasValue := OldHasValue;
 end
 else
 SetValueB := True;
 end;
 
 function ClassifierLevel2Type.GetValueA;
 begin
 if HasValue and (ValueIn = @ValueA) then
 begin
 AValue := ValueA;
 GetValueA := True;
 end
 else
 GetValueA := False;
 end;
 
 function ClassifierLevel2Type.GetValueB;
 begin
 if HasValue and (ValueIn = @ValueB) then
 begin
 AValue := ValueB;
 GetValueB := True;
 end
 else
 GetValueB := False;
 end;
 
 constructor ClassifierType.Create;
 begin
 Level1.Create;
 Level2.Create(@Level1);
 Level1.SetNextLevel(@Level2);
 end;
 
 function ClassifierType.GetLevel1Pointer;
 begin
 GetLevel1Pointer := @Level1;
 end;
 
 function ClassifierType.GetLevel2Pointer;
 begin
 GetLevel2Pointer := @Level2;
 end;
 
 end.
 Тестовая программа: { Тестовая программа для прототипа реализации иерархического классификатора. }program TestClassifier(Input, Output);
 
 uses Classifier;
 
 procedure WriteResult(Message: string; Result: Boolean);
 begin
 Write(Message, ' => ');
 if Result then
 WriteLn('Успешно.')
 else
 WriteLn('Неудачно.');
 end;
 
 var
 ClassifierInstance: ClassifierType;
 Value: EnumType;
 ValueA: EnumAType;
 ValueB: EnumBType;
 begin
 WriteLn('Тесты классификатора (A(C D) B(E F)).');
 ClassifierInstance.Create;
 WriteResult('Установить A в уровне 1',
 ClassifierInstance.GetLevel1Pointer^.SetValue(A));
 WriteResult('Уровень 1 имеет значение',
 not ClassifierInstance.GetLevel1Pointer^.IsEmpty);
 WriteResult('Прочитать из уровня 1 значение',
 ClassifierInstance.GetLevel1Pointer^.GetValue(Value));
 WriteResult('Значение в уровне 1 равно A',
 Value = A);
 WriteResult('Не установить F в уровне 2',
 not ClassifierInstance.GetLevel2Pointer^.SetValueB(F));
 WriteResult('Уровень 2 не имеет значения',
 ClassifierInstance.GetLevel2Pointer^.IsEmpty);
 WriteResult('Установить C в уровне 2',
 ClassifierInstance.GetLevel2Pointer^.SetValueA(C));
 WriteResult('Уровень 2 имеет значение',
 not ClassifierInstance.GetLevel2Pointer^.IsEmpty);
 WriteResult('Прочитать из уровня 2 значение типа A',
 ClassifierInstance.GetLevel2Pointer^.GetValueA(ValueA));
 WriteResult('Значение типа A в уровне 2 равно C',
 ValueA = C);
 WriteResult('Не прочитать из уровня 2 значение типа B',
 not ClassifierInstance.GetLevel2Pointer^.GetValueB(ValueB));
 WriteResult('Не установить B в уровне 1',
 not ClassifierInstance.GetLevel1Pointer^.SetValue(B));
 ClassifierInstance.GetLevel1Pointer^.Clear;
 WriteLn('Очистить уровень 1.');
 WriteResult('Уровень 1 не имеет значения',
 ClassifierInstance.GetLevel1Pointer^.IsEmpty);
 WriteResult('Не прочитать из уровня 1 значение',
 not ClassifierInstance.GetLevel1Pointer^.GetValue(Value));
 WriteResult('Установить F в уровне 2',
 ClassifierInstance.GetLevel2Pointer^.SetValueB(F));
 WriteResult('Не установить A в уровне 1',
 not ClassifierInstance.GetLevel1Pointer^.SetValue(A));
 ClassifierInstance.GetLevel2Pointer^.Clear;
 WriteLn('Очистить уровень 2.');
 WriteResult('Не прочитать из уровня 2 значение типа A',
 not ClassifierInstance.GetLevel2Pointer^.GetValueA(ValueA));
 WriteResult('Не прочитать из уровня 2 значение типа B',
 not ClassifierInstance.GetLevel2Pointer^.GetValueB(ValueB));
 WriteResult('Установить A в уровне 1',
 ClassifierInstance.GetLevel1Pointer^.SetValue(A));
 end.
 Протокол тестирования: Тесты классификатора (A(C D) B(E F)).Установить A в уровне 1 => Успешно.
 Уровень 1 имеет значение => Успешно.
 Прочитать из уровня 1 значение => Успешно.
 Значение в уровне 1 равно A => Успешно.
 Не установить F в уровне 2 => Успешно.
 Уровень 2 не имеет значения => Успешно.
 Установить C в уровне 2 => Успешно.
 Уровень 2 имеет значение => Успешно.
 Прочитать из уровня 2 значение типа A => Успешно.
 Значение типа A в уровне 2 равно C => Успешно.
 Не прочитать из уровня 2 значение типа B => Успешно.
 Не установить B в уровне 1 => Успешно.
 Очистить уровень 1.
 Уровень 1 не имеет значения => Успешно.
 Не прочитать из уровня 1 значение => Успешно.
 Установить F в уровне 2 => Успешно.
 Не установить A в уровне 1 => Успешно.
 Очистить уровень 2.
 Не прочитать из уровня 2 значение типа A => Успешно.
 Не прочитать из уровня 2 значение типа B => Успешно.
 Установить A в уровне 1 => Успешно.
 
Оно хоть всё и логично, но, по-моему, весьма громоздко. И громоздко потому, что типы участвующих в операциях переменных жёстко определены во время компиляции. |  
						| 
								|  |  
								| « Последнее редактирование: 11-10-2008 12:56 от dimka » |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Finch 
								СпокойныйАдминистратор    Offline 
								Пол:    
								Пролетал мимо
								
								
								
								
								
							 | 
								|  | « Ответ #9 : 11-10-2008 14:29 »  |  | 
 
 Я с Variant типом знаком по QVariant из библиотеки Qt. Судя по тому, что я видел в этом классе, он тоже знает все типы еше на стадии компиляции, и со всеми типами он умеет обрашаться. Теперь при, задании ему какого либо значения, тип  которого он не знает, вызовет у него панику, еше на стадии компиляции, так как, компилятор не может подобрать соответствующий метод обработки.  |  
						| 
								|  |  
								|  |  Записан | 
 
 Не будите спашяго дракона.              Джаффар (Коша) |  |  | 
	| 
			| 
					
						| zubr 
								Гость
 | 
								|  | « Ответ #10 : 12-10-2008 14:11 »  |  | 
 
 Как вариант: Класс, создающий древовидный список из классов-элементов, описывающих элемент классификатора. Вот примерный интерфейс на объектном паскале: PClassifierType = ^TClassifierType;TClassifierType = class(TObject)
 private
 FNext: PClassifierType;
 FPrev: PClassifierType;
 FParent: PClassifierType;
 FChild: PClassifierType;
 FData: Pointer;
 FName: string;
 public
 property Next: PClassifierType read FNext write FNext;
 property Prev: PClassifierType read FPrev write FPrev;
 property Parent: PClassifierType read FParent write FParent;
 property Child: PClassifierType read FChild write FChild;
 property Data: Pointer read FData write FData;
 property Name: string read FName write FName;
 
 constructor Create; overload;
 destructor Destroy; override;
 end;
 
 PClassifier = ^TClassifier;
 TClassifier = class(TObject)
 public
 //получение массива строк возможных классов (типа 'BAC', 'BAB', 'BPL') для конкретного класса
 function GetPossebleClassString(ClassifierType: TClassifierType;
 ClassifierList: TStrings): boolean;
 //создает новый классифиткатор на основе имеющегося
 function CreateNewClassifier(const ClassifierArray: Variant;
 LenArray: Integer): PClassifier; overload;
 //создает новый классифиткатор на основе имеющегося по строке
 function CreateNewClassifier(const ClassifierString: string): PClassifier; overload;
 constructor Create(const ClassifierArray: Variant; LenArray: Integer); overload;
 destructor Destroy; override;
 end;
 
Пример создания вышеуказанного класса: varA, B, C, D: TClassifierType;
 Classifier: TClassifier;
 v: Variant;
 
 begin
 A := TClassifierType.Create;
 A.Name := 'A';
 B := TClassifierType.Create;
 B.Name := 'B';
 C := TClassifierType.Create;
 C.Name := 'C';
 D := TClassifierType.Create;
 D.Name := 'D';
 
 v := VarArrayOf([Integer(B), '(', Integer(A), '(', Integer(C), Integer(B), ')', ')']);
 Classifier := TClassifier.Create(v, 8);
 
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #11 : 12-10-2008 17:44 »  |  | 
 
 zubr, не вполне уловил интерфейс - т.е. как пользователю удобно работать с такими классами. Где и как задаются базовые константы, с которыми пользователь будет сравнивать части классификатора?
 Вообще, последовательности констант в классификаторе образуют слова некоторого простого языка, а сам классификатор - его грамматика + средство контроля составления пользователем слов такого языка (синтаксический анализатор).
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| zubr 
								Гость
 | 
								|  | « Ответ #12 : 12-10-2008 19:01 »  |  | 
 
 1) описывал(и) значение классификатора; constructor Create(const ClassifierArray: Variant; LenArray: Integer); overload; - здесь в конструкторе создается древовидный список описывающий древовидную структуру классификатора. Предварительно создается массив указателей на созданные элементы классификатора и скобки, обозначающие иерархию. 2) позволял(и) бы пользователю читать отдельные позиции классификационного кода (поскольку они имеют самостоятельный смысл); function GetPossebleClassString(ClassifierType: TClassifierType; ClassifierList: TStrings): boolean; - метод по объекту элемента (можно сделать по имени) возращает список всех возможных вариантов классификатора, начиная с указанного элемента, к примеру для объекта A - вернется список 'AC', 'AB'. позволял(и) бы конструировать классификационный код в рамках допустимых классификатором возможностей - записывать отдельные позиции классификационного кода. function CreateNewClassifier(const ClassifierArray: Variant; LenArray: Integer): PClassifier; - создание нового древовидного списка, сохраняя структуру базового З.Ы. Интерфейс приблизительный и требует доработки. З.Ы.З.Ы. Может я не правильно понял задачу? |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #13 : 12-10-2008 19:58 »  |  | 
 
 zubr, а зачем пользователю получать список всех возможных вариантов? Тогда уж проще взять их все и перечислить в enum-е... |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| zubr 
								Гость
 | 
								|  | « Ответ #14 : 12-10-2008 21:18 »  |  | 
 
 dimka, ну пусть это будет промежуточный внутренний метод класса, а для сравнения с пользовательской частью классификатора можно будет сделать что то типа:function GetPossebleClassString(const ClassifierName: string; ClassifierList: TStrings): boolean; - где ClassifierName - имя первого элемента
 function CompareClassifier(const UserClassifier:string):boolean; - метод внутри которого будет вызван GetPossebleClassString и из полученного списка сравниваться с UserClassifier
 Вариант перечисления в энуме не может работать в рантайм. В варианте же с древовидным списком можно классификатор формировать любой глубины вложенности, причем динамически.
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	|  |