Disclaimer: нашел статью у себя в черновиках. Писал года полтора-два назад, почему не опубликовал — не помню. Просмотрел, вроде, не совсем бесполезная, пусть будет в открытом доступе.
В последнее время стало достаточно актуальным использование domain specific languages (DSL) — языков «заточенных» под конкретную предметную область. Слово «язык» в данном контексте не обязательно подразумевает именно новый язык программирования, зачастую можно обойтись и старым добрым.
На хабре не замечено ни одной статьи про fluent interface в контексте джавы, так что хотел бы поделиться своим опытом применения.
Спасибо Алепару (alepar) за наводку на статью Фаулера (большого фаната DSL)
Идея fluent interface в том, что API представляет собой некоторое подмножество домен-ориентированного языка описания. Причем это счастье доступно из базового языка программирования.
Текст Фаулера можно почитать по ссылке, я же приведу свой пример.
Допустим, нам нужно программно сконструировать объект соответствующий вот этому xml:
Смысл написанного в том, что у юнита 123 общее значение 4, которое складывается из 3 на дату 777 и еще 1 на дату 888. А у юнита 321 общее значение 5, которое целиком пришлось на дату 888.
API которое используется для построения такого объекта является надстройкой над плюсами (JNI):
В общем все по делу, придраться не к чему, но читать и представлять себе что будет в результате практически нереально …
Изначально это нужно было для юнит теста, поэтому использовать код с неочевидным результатом — не очень удачная идея, т.к. теряется наглядность юнит теста и его документирующая составляющая.
Я крепко подумал и попытался изобразить fluent interface для того же самого. Его реализация оказалась на удивление нетривиальной (из-за особенностей underlying JNI интерфейса), но зато выглядит он очень симпатично:
В общем-то, освоив несколько приемов построения DSL на Java, задача становится технической: глаза боятся, руки делают.
В последнее время стало достаточно актуальным использование domain specific languages (DSL) — языков «заточенных» под конкретную предметную область. Слово «язык» в данном контексте не обязательно подразумевает именно новый язык программирования, зачастую можно обойтись и старым добрым.
На хабре не замечено ни одной статьи про fluent interface в контексте джавы, так что хотел бы поделиться своим опытом применения.
Спасибо Алепару (alepar) за наводку на статью Фаулера (большого фаната DSL)
Идея fluent interface в том, что API представляет собой некоторое подмножество домен-ориентированного языка описания. Причем это счастье доступно из базового языка программирования.
Текст Фаулера можно почитать по ссылке, я же приведу свой пример.
Допустим, нам нужно программно сконструировать объект соответствующий вот этому xml:
<Results> <unit>123</unit> <unit>321</unit> <ResultSet> <ResultsType> <ResultType>ABC</ResultType> <resAllTime>4.000000000000000</resAllTime> <resAllTime>5.000000000000000</resAllTime> <ResultsTimeBucket> <bucketDate>777</bucketDate> <value>3.000000000000000</value> <value>0.000000000000000</value> </ResultsTimeBucket> <ResultsTimeBucket> <bucketDate>888</bucketDate> <value>1.000000000000000</value> <value>5.000000000000000</value> </ResultsTimeBucket> </ResultsType> </ResultSet> </Results>
Смысл написанного в том, что у юнита 123 общее значение 4, которое складывается из 3 на дату 777 и еще 1 на дату 888. А у юнита 321 общее значение 5, которое целиком пришлось на дату 888.
API которое используется для построения такого объекта является надстройкой над плюсами (JNI):
Results r = new Results(); r.CallocResults(new int[] {123, 321}, new int[] {777, 888}); r.SetValue(4.0, "ABC", 0); // 0 - unit index in this case corresponds to "123" r.SetValue(5.0, "ABC", 1); r.SetBucketedValue(3.0, "ABC", 0, 0); r.SetBucketedValue(1.0, "ABC", 1, 0); // 1 - bucketDate index (corresponds to 888), 0 - unit index r.SetBucketedValue(5.0, "ABC", 1, 1);
В общем все по делу, придраться не к чему, но читать и представлять себе что будет в результате практически нереально …
Изначально это нужно было для юнит теста, поэтому использовать код с неочевидным результатом — не очень удачная идея, т.к. теряется наглядность юнит теста и его документирующая составляющая.
Я крепко подумал и попытался изобразить fluent interface для того же самого. Его реализация оказалась на удивление нетривиальной (из-за особенностей underlying JNI интерфейса), но зато выглядит он очень симпатично:
Results r = new ResultsBuilder() .withUnits(123, 321) .result("ABC") .value(123, 4.) .value(321, 5.) .on(777) .value(123, 3.) .on(888) .value(123, 1.) .value(321, 5.) .build();
В общем-то, освоив несколько приемов построения DSL на Java, задача становится технической: глаза боятся, руки делают.
