Здравствуйте, minstrel_, Вы писали:
_>День добрый!
_>Столкнулся я сейчас с проблемой читабельности собственного кода.
_>Пишу я сейчас на BuilderC++ + Oracle. Приходится строить множество динам. запросов в Builder-e, ветвлений при построении запросов тоже множество.
_>Буду благодарен за любые соображения по поводу улучшения читабельности такого кода или за полезные ссылки по этой теме.
на тему построения запросов... я тоже их строю, но спрятал это дело под некий граф. т.е. реально я строю граф, а потом просто преобразую его в запрос. и еще меня притомило, то что ошибки генерации выползают только в ран-тайме... поэтому изыскивалась возможность максимально много вытащить в компайл-тайм...
сделать это в общем-то просто: надо сгенерить "предикаторы" — набор классов по составу полей таких же как и "основные" классы, но....
(забегая вперед) в итоге получаем вот такое:
using System;
namespace Predicators
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
DocumentPredicate dp1 = new DocumentPredicate("Doc1");
DocumentPredicate dp2 = new DocumentPredicate("Doc2");
_BasePredicate bp;
Console.WriteLine("тестируем сравнения с константами");
bp = (dp1.ID == 5 | dp1.doc_type.Name == "asdf");
Console.WriteLine(bp);
Console.WriteLine();
Console.WriteLine("тестируем сравнения с предикатами");
bp = (dp1.doc_type == dp2.doc_type | dp1 == dp2);
Console.WriteLine(bp);
Console.WriteLine();
Console.WriteLine("тестируем сравнения с объектами");
Document d = new Document();
d.doc_type = new DocType();
d.doc_type.Name = "fdsa";
bp = (dp1.doc_type == d.doc_type | dp1.doc_type.Name == d.doc_type.Name);
Console.WriteLine(bp);
Console.WriteLine();
Console.ReadLine();
}
}
}
которое выводит нам вот это:
тестируем сравнения с константами
((Doc1.ID == [5])|(Doc1.doc_type.Name == [asdf]))
тестируем сравнения с предикатами
((Doc1.doc_type.ID == Doc2.doc_type.ID)|(Doc1.ID == Doc2.ID))
тестируем сравнения с объектами
((Doc1.doc_type.ID == [1017528716])|(Doc1.doc_type.Name == [fdsa]))
[offtop]у меня "это дело" (в смысле предикаторы) строят сложные запросы с разнообразными join-нами)[/offtop]
кому лениво выдирать исходники отсюда — файл Predicators.rar (6,06 KB) успешно загружен и доступен по адресу
http://www.rsdn.ru:80/File/11709/Predicators.rar
теперь немного о то м как мы этого добились... а добились мы этого очень просто (голимая техника, легко обуваемая генератором, у меня, кста, оно именно генерится). привожу простейший случай для пары классов:
класс Document из двух полей
Int32 ID; // унаследованно от базового класса DBMapper
DocType doc_type;
и DocType в свою очередь состоит тоже из двух полей:
Int32 ID; // унаследованно от базового класса DBMapper
string Name
так вот... а, да что тут рассказывать... в общем вот:
.
using System;
namespace Predicators
{
//
// исходные классы
//
public class DBMapper
{
internal int ID = new Random().Next();
}
public class Document : DBMapper
{
public DocType doc_type;
}
public class DocType : DBMapper
{
public string Name;
}
//
// придикатные классы
//
public class _BasePredicate
{
protected string PropName;
public _BasePredicate(string APropName)
{
PropName = APropName;
}
//
// единственная задача базового предиката обраьатывать логические операторы и собственно возвращать полученое строковое "значение"
//
protected static _BasePredicate Evaluate(_BasePredicate bp1, _BasePredicate bp2, string _operator)
{
return new _BasePredicate("(" + bp1.PropName + _operator + bp2.PropName + ")");
}
public static _BasePredicate operator & (_BasePredicate bp1, _BasePredicate bp2)
{
return Evaluate(bp1, bp2, "&");
}
public static _BasePredicate operator | (_BasePredicate bp1, _BasePredicate bp2)
{
return Evaluate(bp1, bp2, "|");
}
public override string ToString()
{
return PropName;
}
}
//
// по сути этот класс (в данном случае) нужен только для того что бы у всех бы ID
//
public class DBMapperPredicate : _BasePredicate
{
internal Int32Predicate ID;
public DBMapperPredicate(string APropName) : base (APropName)
{
ID = new Int32Predicate(PropName + ".ID");
}
}
public class DocumentPredicate : DBMapperPredicate
{
public DocTypePredicate doc_type;
public DocumentPredicate(string APropName) : base (APropName)
{
doc_type = new DocTypePredicate(PropName + ".doc_type");
}
// перекрываем операторы сравнения (==, !=, <=, >= и т.д.
// обращаю внимание на то, что в "перекрытии" операторов используются уже "перекрытые" операторы ;)
// с чем нас и поздравляю ибо писать "Эвалуатор" нам не пришлось. ура!
public static _BasePredicate operator == (DocumentPredicate pred, Document obj)
{
return pred.ID == obj.ID; // pred.ID и obj.ID есть ни что иное как Int32Predicate...
}
public static _BasePredicate operator == (DocumentPredicate pred1, DocumentPredicate pred2)
{
return pred1.ID == pred2.ID;
}
public static _BasePredicate operator != (DocumentPredicate pred, Document obj)
{
return pred.ID != obj.ID; // а вот здесь мы уже сравнивает предикат pred.ID и значение поля obj.ID
}
public static _BasePredicate operator != (DocumentPredicate pred1, DocumentPredicate pred2)
{
return pred1.ID != pred2.ID;
}
// ..................
//
// и т.д
// и т.п.
//
// ..................
// это "обязаловка", если мы занялись "перекрытием" операторов
public override Int32 GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
}
// ничем (в техническом смысле) не отличается от DocumentPredicate
public class DocTypePredicate : DBMapperPredicate
{
public StringPredicate Name;
public DocTypePredicate(string APropName) : base (APropName)
{
Name = new StringPredicate(PropName + ".Name");
}
public static _BasePredicate operator == (DocTypePredicate pred, DocType obj)
{
return pred.ID == obj.ID;
}
public static _BasePredicate operator == (DocTypePredicate pred1, DocTypePredicate pred2)
{
return pred1.ID == pred2.ID;
}
public static _BasePredicate operator != (DocTypePredicate pred, DocType obj)
{
return pred.ID != obj.ID;
}
public static _BasePredicate operator != (DocTypePredicate pred1, DocTypePredicate pred2)
{
return pred1.ID != pred2.ID;
}
public override Int32 GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
}
//
// а вот пошли ValueType предикаты
//
// собственно на них лежит основная "ответсвенность"
//
public class StringPredicate
{
string PropName;
public StringPredicate(string APropName)
{
PropName = APropName;
}
// парочка эвалуаторов, результат работы которых - новый базовый предикат.
// суть - строим выражение путем расставления скобок и операторов между частями выражения
protected static _BasePredicate Evaluate(StringPredicate obj_pred, String obj, string _operator)
{
return new _BasePredicate("(" + obj_pred.PropName + _operator + "[" + obj.ToString() + "])");
}
protected static _BasePredicate Evaluate(StringPredicate obj_pred1, StringPredicate obj_pred2, string _operator)
{
return new _BasePredicate("(" + obj_pred1.PropName + _operator + obj_pred2.PropName + ")");
}
//
// перекрываем операторы. всё просто...
//
public static _BasePredicate operator == (StringPredicate obj_pred, String obj)
{
return Evaluate(obj_pred, obj, " == ");
}
public static _BasePredicate operator == (StringPredicate obj_pred, StringPredicate obj_pred2)
{
return Evaluate(obj_pred, obj_pred2, " == ");
}
public static _BasePredicate operator != (StringPredicate obj_pred, String obj)
{
return Evaluate(obj_pred, obj, " != ");
}
public static _BasePredicate operator != (StringPredicate obj_pred, StringPredicate obj_pred2)
{
return Evaluate(obj_pred, obj_pred2, " != ");
}
public override Int32 GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
}
//
// тоже самое что и для Int32Predicate
public class Int32Predicate
{
string PropName;
public Int32Predicate(string APropName)
{
PropName = APropName;
}
protected static _BasePredicate Evaluate(Int32Predicate obj_pred, Int32 obj, string _operator)
{
return new _BasePredicate("(" + obj_pred.PropName + _operator + "[" + obj.ToString() + "])");
}
protected static _BasePredicate Evaluate(Int32Predicate obj_pred1, Int32Predicate obj_pred2, string _operator)
{
return new _BasePredicate("(" + obj_pred1.PropName + _operator + obj_pred2.PropName + ")");
}
public static _BasePredicate operator == (Int32Predicate obj_pred, Int32 obj)
{
return Evaluate(obj_pred, obj, " == ");
}
public static _BasePredicate operator == (Int32Predicate obj_pred, Int32Predicate obj_pred2)
{
return Evaluate(obj_pred, obj_pred2, " == ");
}
public static _BasePredicate operator != (Int32Predicate obj_pred, Int32 obj)
{
return Evaluate(obj_pred, obj, " != ");
}
public static _BasePredicate operator != (Int32Predicate obj_pred, Int32Predicate obj_pred2)
{
return Evaluate(obj_pred, obj_pred2, " != ");
}
public override Int32 GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
}
}
.
финита...
вы спросите: "А где же граф?"... а я отвечу: "А здесь его и нету

"... граф я реализую у себя для анализа запроса и оптимизации оного...
... << RSDN@Home 1.1.3 beta 1 >>