читабельность
От: minstrel_  
Дата: 12.05.04 15:42
Оценка:
День добрый!
Столкнулся я сейчас с проблемой читабельности собственного кода.
Пишу я сейчас на BuilderC++ + Oracle. Приходится строить множество динам. запросов в Builder-e, ветвлений при построении запросов тоже множество.
Буду благодарен за любые соображения по поводу улучшения читабельности такого кода или за полезные ссылки по этой теме.
Re: читабельность
От: _MarlboroMan_ Россия  
Дата: 12.05.04 18:41
Оценка: 60 (2)
Здравствуйте, 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 >>

— сколько программистов надо чтобы заменить сгоревшую лампочку?
— сколько не бери, а лампочку не поменять — проблема аппаратная, программным путем не решается...
Re: читабельность
От: Mike_kv4  
Дата: 13.05.04 09:46
Оценка:
Здравствуйте, minstrel_, Вы писали:
>Буду благодарен за любые соображения по поводу улучшения читабельности такого кода или за полезные ссылки по этой теме.

Я бы посоветовал глянуть в книгу Мартина Фаулера
"Архитектура корпоративных программных приложений"
М: "Вильямс", 2004 г, 544 стр.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.