精华内容
下载资源
问答
  • Intersil公司(纳斯达克全球精选市场交易代码:ISIL)宣布,针对迅猛增长的VDSL2超高比特率互联网连接标准应用而推出DSL线路驱动器家族中的最新成员ISL1539A。  ISL1539A同时支持8MHz和17MHz的VDSL2规格,兼容广泛...
  • DSL技术

    2018-03-18 19:48:00
    当传统的调制解调器达到其最高数据率后,电话公司有开发出了另外一种技术,即DSL(数字用户线技术),它可以提供到因特网的高速写入。数字用户线技术是使用现有的本地用户线(电话线)来支持高速数字通信的一种最有...

    当传统的调制解调器达到其最高数据率后,电话公司有开发出了另外一种技术,即DSL(数字用户线技术),它可以提供到因特网的高速写入。数字用户线技术是使用现有的本地用户线(电话线)来支持高速数字通信的一种最有前途的技术。DSL技术是一组技术的统称,其中每种技术以不同的首字母来区分(ADSL,VDSL,HDSL,SDSL)这组技术通常被记为xDSL,这里的x可以是,A,V,H,S。

    1、ADSL:(非对称数字用户线技术)

    像56k调制解调器一样,ADSL,在下行方向(从因特网到用户)可以提供比上行方向(从用户到因特网)更高的速率(比特率)。这就是它被称为非对称的原因。与56k调制解调器的非对称不同的是ADSL的设计者特意不平均的分割了本地环路中居民用户的可用带宽。这种服务不适用于企业用户,因为他们在两个方向都需要大的带宽。

    非对称数字用户线技术ADSL是一种为居民用户设计的非对称通信技术,他不适用与企业。

    带宽是如何划分的:

    语音:信道0为语音通信保留。

    空闲:信道1-5没有使用,以便在话音和数据通信之间留有间隙。、

    上行数据和控制:信道6-30(25个信道)用于上行数据的传送和控制。一个信道用于控制,24个信道用于数据传送。如果有24个信道,每个信道使用4khz(在4312khz的可用带宽之中),在每赫兹15位的的条件之下,我么在上行方向

    有24*4000*15=1.44Mbps带宽。

    下行数据和带宽:信道31-255(225个信道)用于下行数据的传送和控制。一个信道用于控制,其他244个信道用于数据的传送和控制。如果是全部的224个信道,我们就可以这样,224*400*15=13.4Mbps的带宽。

    由于信噪比较高,世纪的比特率要大大低于以上的数值。上行:64kbs-1Mbps,下行:500kbps-8Mbps。

    安装在用户端的一个ADSL调制解调器。本地环路连接到一个过滤器,其作用是把话音通信和数据通信分开。ADSL调制解调器对数据进行调制并建立下行和上行信道。

    而安装在电话公司的情况就有所不同了。这里不使用ADSL调制解调器,而是安装了称为数字用户线接入复用器(DSLAM)的设备,其功能与ADSL调制解调器是相似的。除此之外,他还要把即将发送到因特网的数据打包。

    2、其他DSL技术

    ADSL提供了非对称的的通信,下行数据率大大高于上行数据率。虽然这一特点可以是绝大多数用户满意,但它并不适合与企业用户(两个方向都有大量数据要发送和接受)。对称数字用户线技术(SDSL),就是为这些企业设计的,它可以把带宽平均分配到上行和下行。

    3、高数据率数字用户线(HDSL)使用了传号交替反转(AMI)编码,这使得他在高频端对对衰减很敏感,因此T-1线的长度限制在1公里内。对于更远的距离就必须安装转发器(增加了成本)。

    4、甚高数据率数字用户线(VDSL):是类似ADSL的另一种技术,它使用同轴电缆、光缆以及双绞线电缆,用于短距离传输(30-1800m)。其调制技术为离散多音技术(DMT),下行数据率是50-55Mbps,上行是1.5Mbps。

    转载于:https://www.cnblogs.com/yjds/p/8597038.html

    展开全文
  • query dsl

    2018-08-23 16:22:17
    另外可以参考:https://blog.csdn.net/liuchuanhong1/article/details/70244261?utm_source=gold_browser_extension ...最近再看公司项目中有如下代码,看了后简直不能忍.缺点列出来的话,如下: 返回类型Obje...

    另外可以参考:https://blog.csdn.net/liuchuanhong1/article/details/70244261?utm_source=gold_browser_extension

    转自:https://www.jianshu.com/p/2b68af9aa0f5

    1.问题的提出

    最近再看公司项目中有如下代码,看了后简直不能忍.缺点列出来的话,如下:

    1. 返回类型Object[]数组,至于每一个下标对应哪个字段,没法直观的看到,例如object[11]是什么类型?字段名是什么?这个就无法直观得知.
    2. sql中复杂的关系导致不可维护,每一个接手的人都要研究sql半天
    3. 该种动态拼接条件方法导致类似的代码会大量重复,所以IDEA打开的时候黄了半边天.
    4. 该查询为分页查询,这样写的话,还要再copy一个count查询才能拿到总数,无疑又是代码重复.
    5. JPA这种框架目的就是少些原生sql语句,大量这样的操作的话,还不如使用dbUtil这样的工具类查询.
        @Override
        public List<Object[]> findByPcardCardOrder(
                PcardCardOrder pcardCardOrder,String applyInstName2,Integer page, Integer rows) {
            StringBuffer sql = new StringBuffer(
                    "SELECT p.*"
                            +",p2.vcard_make_des" 
                            +",p3.cardnum_rule_id,p3.vtype_nm"
                            +",p4.cn_card_bin,p4.cn_nm"
                            +",p5.inst_id,p5.inst_name,p5.apply_range,p5.card_name,p5.card_type,p5.bin_card_material"
                            +",p6.inst_name AS apply_inst_name "
                            +",p7.inst_name AS apply_inst_name2"
                            + ",p8.inst_name as receive_inst_name"
                            + " FROM "
                            +" tbl_pcard_card_order p LEFT JOIN tbl_pcard_vcard_make p2 ON p.make_id = p2.vcard_make_id"
                         +" LEFT JOIN  tbl_pcard_vtype p3 ON p2.vcard_make_vtype_id=p3.vtype_id"
                         +" LEFT JOIN  tbl_pcard_cardnum_rule p4 ON p3.cardnum_rule_id=p4.cn_id"
                         +" LEFT JOIN  tbl_pcard_cardbin p5 ON p4.cn_card_bin=p5.card_bin"
                         +" LEFT JOIN  tbl_pcard_institution p6 ON p5.apply_range=p6.inst_id"
                         +" LEFT JOIN  tbl_pcard_institution p7 ON p.apply_inst_id=p7.inst_id"
                         +" LEFT JOIN  tbl_pcard_institution p8 ON p.receive_inst=p8.inst_id"
                         +" WHERE 1=1 ");
            int i = 1;
            Map<String, Object> map = new HashMap<String, Object>();
    
            if (!StringUtils.isEmpty(pcardCardOrder.getCordId())) {
                sql.append(" and p.cord_id=");
                sql.append("?" + i);
                map.put(i + "", pcardCardOrder.getCordId());
                i++;
            }
            if (!StringUtils.isEmpty(pcardCardOrder.getAppointMchtcard())) {
                sql.append(" and p.appoint_mchtcard=");
                sql.append("?" + i);
                map.put(i + "", pcardCardOrder.getAppointMchtcard());
                i++;
            }
    
            if (!StringUtils.isEmpty(pcardCardOrder.getMakeId())) {
                sql.append(" and p.make_id like ");
                sql.append("?" + i);
                map.put(i + "","%%"+ pcardCardOrder.getMakeId()+"%%");
                i++;
            }
    
            if (!StringUtils.isEmpty(applyInstName2)) {
                sql.append(" and p7.inst_name like ");
                sql.append("?"+i);
                map.put(i+"","%%"+applyInstName2+"%%");
                i++;
            }
            
            sql.append(" order by p.ct_dm desc");
            Query query = entityManager.createNativeQuery(sql.toString());
            for (String key : map.keySet()) {
                query.setParameter(key, map.get(key));
            }
            if (page != null && rows != null) {
                query.setFirstResult(rows * (page - 1));
                query.setMaxResults(rows);
            }
            return query.getResultList();
        }
    

    2.学习QueryDSL

    queryDSL就可以避免上面全部的问题,在解决问题之前先学习如何使用.

    2.1 QueryDSL简介

    1. QueryDSL仅仅是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查询。
    2. Querydsl可以通过一组通用的查询API为用户构建出适合不同类型ORM框架或者是SQL的查询语句,也就是说QueryDSL是基于各种ORM框架以及SQL之上的一个通用的查询框架。
    3. 借助QueryDSL可以在任何支持的ORM框架或者SQL平台上以一种通用的API方式来构建查询。目前QueryDSL支持的平台包括JPA,JDO,SQL,Java Collections,RDF,Lucene,Hibernate Search。
    4. 官网地址:点击进入

    2.2配置到项目

    首先对于queryDSL有两个版本,com.mysema.querydslcom.querydsl,前者是3.X系列后者是4.X系列,这里使用的是后者.

    第一步:Maven引入依赖:

        <!--query dsl-->
        <dependency>
          <groupId>com.querydsl</groupId>
          <artifactId>querydsl-jpa</artifactId>
          <version>${querydsl.version}</version>
        </dependency>
        <dependency>
          <groupId>com.querydsl</groupId>
          <artifactId>querydsl-apt</artifactId>
          <version>${querydsl.version}</version>
          <scope>provided</scope>
        </dependency>
        <!--query dsl end-->
    

    第二步:加入插件,用于生成查询实例

    <!--该插件可以生成querysdl需要的查询对象,执行mvn compile即可-->
          <plugin>
            <groupId>com.mysema.maven</groupId>
            <artifactId>apt-maven-plugin</artifactId>
            <version>1.1.3</version>
            <executions>
              <execution>
                <goals>
                  <goal>process</goal>
                </goals>
                <configuration>
                  <outputDirectory>target/generated-sources/java</outputDirectory>
                  <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                </configuration>
              </execution>
            </executions>
          </plugin>
    

    执行mvn compile之后,可以找到该target/generated-sources/java,然后IDEA标示为源代码目录即可.

    1.jpg

     

    2.3实体类

    城市类:

    @Entity
    @Table(name = "t_city", schema = "test", catalog = "")
    public class TCity {
        //省略JPA注解标识
        private int id;
        private String name;
        private String state;
        private String country;
        private String map;
    }
    

    旅馆类:

    @Entity
    @Table(name = "t_hotel", schema = "test", catalog = "")
    public class THotel {
        //省略JPA注解标识
        private int id;
        private String name;
        private String address;
        private Integer city;//保存着城市的id主键
    }
    

    2.4 单表动态分页查询

    Spring Data JPA中提供了QueryDslPredicateExecutor接口,用于支持QueryDSL的查询操作,这样的话单表动态查询就可以参考如下代码:

    //查找出Id小于3,并且名称带有`shanghai`的记录.
    
            //动态条件
            QTCity qtCity = QTCity.tCity;
            //该Predicate为querydsl下的类,支持嵌套组装复杂查询条件
            Predicate predicate = qtCity.id.longValue().lt(3)
                                           .and(qtCity.name.like("shanghai"));
            //分页排序
            Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC,"id"));
            PageRequest pageRequest = new PageRequest(0,10,sort);
            //查找结果
            Page<TCity> tCityPage = tCityRepository.findAll(predicate,pageRequest);
    

    2.5多表动态查询

    QueryDSL对多表查询提供了一个很好地封装,看下面代码:

        /**
         * 关联查询示例,查询出城市和对应的旅店
         * @param predicate 查询条件
         * @return 查询实体
         */
        @Override
        public List<Tuple> findCityAndHotel(Predicate predicate) {
            JPAQueryFactory queryFactory = new JPAQueryFactory(em);
            JPAQuery<Tuple> jpaQuery = queryFactory.select(QTCity.tCity,QTHotel.tHotel)
                                            .from(QTCity.tCity)
                                            .leftJoin(QTHotel.tHotel)
                                            .on(QTHotel.tHotel.city.longValue().eq(QTCity.tCity.id.longValue()));
            //添加查询条件
            jpaQuery.where(predicate);
            //拿到结果
            return jpaQuery.fetch();
        }
    

    城市表左连接旅店表,当该旅店属于这个城市时查询出两者的详细字段,存放到一个Tuple的多元组中.相比原生sql,简单清晰了很多.
    那么该怎么调用这个方法呢?

     @Test
        public void findByLeftJoin(){
            QTCity qtCity = QTCity.tCity;
            QTHotel qtHotel = QTHotel.tHotel;
            //查询条件
            Predicate predicate = qtCity.name.like("shanghai");
            //调用
            List<Tuple> result = tCityRepository.findCityAndHotel(predicate);
            //对多元组取出数据,这个和select时的数据相匹配
            for (Tuple row : result) {
                System.out.println("qtCity:"+row.get(qtCity));
                System.out.println("qtHotel:"+row.get(qtHotel));
                System.out.println("--------------------");
            }
            System.out.println(result);
        }
    

    这样做的话避免了返回Object[]数组,下面是自动生成的sql语句:

    select
            tcity0_.id as id1_0_0_,
            thotel1_.id as id1_1_1_,
            tcity0_.country as country2_0_0_,
            tcity0_.map as map3_0_0_,
            tcity0_.name as name4_0_0_,
            tcity0_.state as state5_0_0_,
            thotel1_.address as address2_1_1_,
            thotel1_.city as city3_1_1_,
            thotel1_.name as name4_1_1_ 
        from
            t_city tcity0_ 
        left outer join
            t_hotel thotel1_ 
                on (
                    cast(thotel1_.city as signed)=cast(tcity0_.id as signed)
                ) 
        where
            tcity0_.name like ? escape '!'
    

    2.6 多表动态分页查询

    分页查询对于queryDSL无论什么样的sql只需要写一遍,会自动转换为相应的count查询,也就避免了文章开始的问题4,下面代码是对上面的查询加上分页功能:

          @Override
        public QueryResults<Tuple> findCityAndHotelPage(Predicate predicate,Pageable pageable) {
            JPAQueryFactory queryFactory = new JPAQueryFactory(em);
            JPAQuery<Tuple> jpaQuery = queryFactory.select(QTCity.tCity.id,QTHotel.tHotel)
                                                   .from(QTCity.tCity)
                                                   .leftJoin(QTHotel.tHotel)
                                                   .on(QTHotel.tHotel.city.longValue().eq(QTCity.tCity.id.longValue()))
                                                   .where(predicate)
                                                   .offset(pageable.getOffset())
                                                   .limit(pageable.getPageSize());
            //拿到分页结果
            return jpaQuery.fetchResults();
        }
    

    和上面不同之处在于这里使用了offsetlimit限制查询结果.并且返回一个QueryResults,该类会自动实现count查询和结果查询,并进行封装.
    调用形式如下:

        @Test
        public void findByLeftJoinPage(){
            QTCity qtCity = QTCity.tCity;
            QTHotel qtHotel = QTHotel.tHotel;
            //条件
            Predicate predicate = qtCity.name.like("shanghai");
            //分页
            PageRequest pageRequest = new PageRequest(0,10);
            //调用查询
            QueryResults<Tuple> result = tCityRepository.findCityAndHotelPage(predicate,pageRequest);
            //结果取出
            for (Tuple row : result.getResults()) {
                System.out.println("qtCity:"+row.get(qtCity));
                System.out.println("qtHotel:"+row.get(qtHotel));
                System.out.println("--------------------");
            }
            //取出count查询总数
            System.out.println(result.getTotal());
        }
    

    生成的原生count查询sql,当该count查询结果为0的话,则直接返回,并不会再进行具体数据查询:

        select
            count(tcity0_.id) as col_0_0_ 
        from
            t_city tcity0_ 
        left outer join
            t_hotel thotel1_ 
                on (
                    cast(thotel1_.city as signed)=cast(tcity0_.id as signed)
                ) 
        where
            tcity0_.name like ? escape '!'
    

    生成的原生查询sql:

       select
            tcity0_.id as id1_0_0_,
            thotel1_.id as id1_1_1_,
            tcity0_.country as country2_0_0_,
            tcity0_.map as map3_0_0_,
            tcity0_.name as name4_0_0_,
            tcity0_.state as state5_0_0_,
            thotel1_.address as address2_1_1_,
            thotel1_.city as city3_1_1_,
            thotel1_.name as name4_1_1_ 
        from
            t_city tcity0_ 
        left outer join
            t_hotel thotel1_ 
                on (
                    cast(thotel1_.city as signed)=cast(tcity0_.id as signed)
                ) 
        where
            tcity0_.name like ? escape '!' limit ?
    

    查看打印,可以发现对应的city也都是同一个对象,hotel是不同的对象.

    Paste_Image.png

    3.改造

    有了上面的经验,改造就变得相当容易了.
    首先前面的一堆sql可以写成如下形式,无非是多了一些select和left join

    JPAQueryFactory factory = new JPAQueryFactory(entityManager);
            factory.select($.pcardCardOrder)
                   .select($.pcardVcardMake.vcardMakeDes)
                   .select($.pcardVtype.cardnumRuleId,$.pcardVtype.vtypeNm)
                   .select($.pcardCardbin)
                   .leftJoin($.pcardVcardMake).on($.pcardCardOrder.makeId.eq($.pcardVcardMake.vcardMakeId))
                   //......省略
    

    查询条件使用Predicate代替,放在service拼接,或者写一个生产条件的工厂都可以.

     jpaQuery.where(predicate);
    

    最后的分页处理就和之前的一样了

            jpaQuery.offset(pageable.getOffset())
                    .limit(pageable.getPageSize());
            return jpaQuery.fetchResults();
    

    个人感觉Query DSL和Spring Data JPA是绝配.更多请参考Demo代码:

    github: https://github.com/nl101531/JavaWEB



    作者:此博废弃_更新在个人博客
    链接:https://www.jianshu.com/p/2b68af9aa0f5
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    参考:

    https://www.jianshu.com/p/4e9d8adaeeb2

    展开全文
  • 最近在公司做了一次有关 DSL 在 iOS 开发中的应用的分享,这篇文章会简单介绍这次分享的内容。 因为 DSL 以及 DSL 的界定本身就是一个比较模糊的概念,所以难免有与他人观点意见相左的地方,如果有不同的意见,我们...
        

    最近在公司做了一次有关 DSL 在 iOS 开发中的应用的分享,这篇文章会简单介绍这次分享的内容。

    因为 DSL 以及 DSL 的界定本身就是一个比较模糊的概念,所以难免有与他人观点意见相左的地方,如果有不同的意见,我们可以具体讨论。

    这次文章的题目虽然是谈谈 DSL 以及 DSL 的应用,不过文章中主要侧重点仍然是 DSL,会简单介绍 DSL 在 iOS 开发中(CocoaPods)是如何应用的。

    没有银弹?

    1987 年,IBM 大型电脑之父 Fred Brooks 发表了一篇关于软件工程中的论文 No Silver Bullet—Essence and Accidents of Software Engineering 文中主要围绕这么一个观点:没有任何一种技术或者方法能使软件工程的生产力在十年之内提高十倍。

    There is no single development, in either technology or management technique, which by itself promises even one order-of-magnitude improvement within a decade in productivity, in reliability, in simplicity.

    时至今日,我们暂且不谈银弹在软件工程中是否存在(这句话在老板或者项目经理要求加快项目进度时,还是十分好用的),作为一个开发者也不是很关心这种抽象的理论,我们更关心的是开发效率能否有实质的提升。

    silver-bullet

    而今天要介绍的 DSL 就可以真正的提升生产力,减少不必要的工作,在一些领域帮助我们更快的实现需求。

    DSL 是什么?

    笔者是在两年以前,在大一的一次分享上听到 DSL 这个词的,但是当时并没有对这个名词有多深的理解与认识,听过也就忘记了,但是最近做的一些开源项目让我重新想起了 DSL,也是这次分享题目的由来。

    DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言(下简称 DSL);而与 DSL 相对的就是 GPL,这里的 GPL 并不是我们知道的开源许可证,而是 General Purpose Language 的简称,即通用编程语言,也就是我们非常熟悉的 Objective-C、Java、Python 以及 C 语言等等。

    Wikipedia 对于 DSL 的定义还是比较简单的:

    A specialized computer language designed for a specific task.

    为了解决某一类任务而专门设计的计算机语言。

    与 GPL 相对,DSL 与传统意义上的通用编程语言 C、Python 以及 Haskell 完全不同。通用的计算机编程语言是可以用来编写任意计算机程序的,并且能表达任何的可被计算的逻辑,同时也是 图灵完备 的。

    这一小节中的 DSL 指外部 DSL,下一节中会介绍 内部 DSL/嵌入式 DSL

    但是在里所说的 DSL 并不是图灵完备的,它们的表达能力有限,只是在特定领域解决特定任务的。

    A computer programming language of limited expressiveness focused on a particular domain.

    另一个世界级软件开发大师 Martin Fowler 对于领域特定语言的定义在笔者看来就更加具体了,DSL 通过在表达能力上做的妥协换取在某一领域内的高效

    而有限的表达能力就成为了 GPL 和 DSL 之间的一条界限。

    几个栗子

    最常见的 DSL 包括 Regex 以及 HTML & CSS,在这里会对这几个例子进行简单介绍

    • Regex

      • 正则表达式仅仅指定了字符串的 pattern,其引擎就会根据 pattern 判断当前字符串跟正则表达式是否匹配。
        regex

    • SQL

      • SQL 语句在使用时也并没有真正的执行,我们输入的 SQL 语句最终还要交给数据库来进行处理,数据库会从 SQL 语句中读取有用的信息,然后从数据库中返回使用者期望的结果。

    • HTML & CSS

      • HTML 和 CSS 只是对 Web 界面的结构语义和样式进行描述,虽然它们在构建网站时非常重要,但是它们并非是一种编程语言,正相反,我们可以认为 HTML 和 CSS 是在 Web 中的领域特定语言。

    Features

    上面的几个?明显的缩小了通用编程语言的概念,但是它们确实在自己领域表现地非常出色,因为这些 DSL 就是根据某一个特定领域的特点塑造的;而通用编程语言相比领域特定语言,在设计时是为了解决更加抽象的问题,而关注点并不只是在某一个领域。

    上面的几个例子有着一些共同的特点:

    • 没有计算和执行的概念;

    • 其本身并不需要直接表示计算;

    • 使用时只需要声明规则、事实以及某些元素之间的层级和关系;

    虽然了解了 DSL 以及 DSL 的一些特性,但是,到目前为止,我们对于如何构建一个 DSL 仍然不是很清楚。

    构建 DSL

    DSL 的构建与编程语言其实比较类似,想想我们在重新实现编程语言时,需要做那些事情;实现编程语言的过程可以简化为定义语法与语义,然后实现编译器或者解释器的过程,而 DSL 的实现与它也非常类似,我们也需要对 DSL 进行语法与语义上的设计。

    compile

    总结下来,实现 DSL 总共有这么两个需要完成的工作:

    1. 设计语法和语义,定义 DSL 中的元素是什么样的,元素代表什么意思

    2. 实现 parser,对 DSL 解析,最终通过解释器来执行

    以 HTML 为例,HTML 中所有的元素都是包含在尖括号 <> 中的,尖括号中不同的元素代表了不同的标签,而这些标签会被浏览器解析成 DOM 树,再经过一系列的过程调用 Native 的图形 API 进行绘制。

    dom-tree

    再比如,我们使用下面这种方式对一个模型进行定义,实现一个 ORM 领域的 DSL:

    define :article do
      attr :name
      attr :content
      attr :upvotes, :int
      
      has_many :comments
    end

    在上面的 DSL 中,使用 define 来定义一个新的模型,使用 attr 来为模型添加属性,使用 has_many 建立数据模型中的一对多关系;我们可以使用 DSL 对这段“字符串”进行解析,然后交给代码生成器来生成代码。

    public struct Article {
        public var title: String
        public var content: String
        public var createdAt: Date
        
        public init(title: String, content: String, createdAt: Date)
    
        static public func new(title: String, content: String, createdAt: Date) -> Article
        static public func create(title: String, content: String, createdAt: Date) -> Article?
        ...
    }

    这里创建的 DSL 中的元素数量非常少,只有 define attr 以及 has_many 等几个关键字,但是通过这几个关键字就可以完成在模型层需要表达的绝大部分语义。

    设计原则和妥协

    DSL 最大的设计原则就是简单,通过简化语言中的元素,降低使用者的负担;无论是 Regex、SQL 还是 HTML 以及 CSS,其说明文档往往只有几页,非常易于学习和掌握。但是,由此带来的问题就是,DSL 中缺乏抽象的概念,比如:模块化、变量以及方法等。

    抽象的概念并不是某个领域所关注的问题,就像 Regex 并不需要有模块、变量以及方法等概念。

    由于抽象能力的缺乏,在我们的项目规模变得越来越大时,DSL 往往满足不了开发者的需求;我们仍然需要编程语言中的模块化等概念对 DSL 进行补充,以此解决 DSL 并不是真正编程语言的问题。

    css-sass

    在当今的 Web 前端项目中,我们在开发大规模项目时往往不会直接手写 CSS 文件,而是会使用 Sass 或者 Less 为 CSS 带来更强大的抽象能力,比如嵌套规则,变量,混合以及继承等特性。

    nav {
      ul {
        margin: 0;
        padding: 0;
        list-style: none;
      }
    
      li { display: inline-block; }
    
      a {
        display: block;
        padding: 6px 12px;
        text-decoration: none;
      }
    }

    也就是说,在使用 DSL 的项目规模逐渐变大时,开发者会通过增加抽象能力的方式,对已有的 DSL 进行拓展;但是这种扩展往往需要重新实现通用编程语言中的特性,所以一般情况下都是比较复杂的。

    Embedded DSL(嵌入式 DSL)

    那么,是否有一种其它的方法为 DSL 快速添加抽象能力呢?而这也就是这一小节的主题,嵌入式 DSL。

    在上一节讲到的 DSL 其实可以被称为外部 DSL;而这里即将谈到的嵌入式 DSL 也有一个别名,内部 DSL。

    这两者最大的区别就是,内部 DSL 的实现往往是嵌入一些编程语言的,比如 iOS 的依赖管理组件 CocoaPods 和 Android 的主流编译工具 Gradle,前者的实现是基于 Ruby 语言的一些特性,而后者基于 Groovy。

    cocoapods

    CocoaPods 以及其它的嵌入式 DSL 使用了宿主语言(host language)的抽象能力,并且省去了实现复杂语法分析器(Parser)的过程,并不需要重新实现模块、变量等特性。

    嵌入式 DSL 的产生其实模糊了框架和 DSL 的边界,不过这两者看起来也没有什么比较明显的区别;不过,DSL 一般会使用宿主语言的特性进行创造,在设计 DSL 时,也不会考虑宿主语言中有哪些 API 以及方法,而框架一般都是对语言中的 API 进行组合和再包装。

    我们没有必要争论哪些是框架,哪些是 DSL,因为这些争论并没有什么意义。

    Rails 和 Embedded DSL

    最出名也最成功的嵌入式 DSL 应该就是 Ruby on Rails 了,虽然对于 Rails 是否是 DSL 有争议,不过 Rails 为 Web 应用的创建提供大量的内置的支撑,使我们在开发 Web 应用时变得非常容易。

    rails

    Ruby、 DSL 和 iOS

    为了保证这篇文章的完整性,这一小节中有的一些内容都出自上一篇文章 CocoaPods 都做了什么?

    笔者同时作为 iOS 和 Rails 开发者接触了非常多的 DSL,而在 iOS 开发中最常见的 DSL 就是 CocoaPods 了,而这里我们以 CocoaPods 为例,介绍如何使用 Ruby 创造一个嵌入式 DSL。

    Why Ruby?

    看到这里有人可能会问了,为什么使用 Ruby 创造嵌入式 DSL,而不是使用 C、Java、Python 等等语言呢,这里大概有四个原因:

    • 一切皆对象的特性减少了语言中的元素,不存在基本类型、操作符;

    • 向 Ruby 方法中传入代码块非常方便;

    • 作为解释执行的语言,eval 模糊了数据和代码的边界;

    • 不对代码的格式进行约束,同时一些约定减少了代码中的噪音。

    一切皆对象

    在许多语言,比如 Java 中,数字与其他的基本类型都不是对象,而在 Ruby 中所有的元素,包括基本类型都是对象,同时也不存在运算符的概念,所谓的 1 + 1,其实只是 1.+(1) 的语法糖而已。

    得益于一切皆对象的概念,在 Ruby 中,你可以向任意的对象发送 methods 消息,在运行时自省,所以笔者在每次忘记方法时,都会直接用 methods 来“查阅文档”:

    2.3.1 :003 > 1.methods
     => [:%, :&, :*, :+, :-, :/, :<, :>, :^, :|, :~, :-@, :**, :<=>, :<<, :>>, :<=, :>=, :==, :===, :[], :inspect, :size, :succ, :to_s, :to_f, :div, :divmod, :fdiv, :modulo, ...]

    比如在这里向对象 1 调用 methods 就会返回它能响应的所有方法。

    一切皆对象不仅减少了语言中类型的数量,消灭了基本数据类型与对象之间的边界;这一概念同时也简化了组成语言的元素,这样 Ruby 中只有对象和方法,这两个概念,极大降低了这门语言的复杂度:

    • 使用对象存储状态

    • 对象之间通过方法通信

    block

    Ruby 对函数式编程范式的支持是通过 block,这里的 block 和 Objective-C 中的 block 有些不同。

    首先 Ruby 中的 block 也是一种对象,即 Proc 类的实例,也就是所有的 block 都是 first-class 的,可以作为参数传递,返回。

    下面的代码演示了两种向 Ruby 方法中传入代码块的方式:

    def twice(&proc)
        2.times { proc.call() } if proc
    end
    
    def twice
        2.times { yield } if block_given?
    end

    yield 会调用外部传入的 block,block_given? 用于判断当前方法是否传入了 block

    twice do 
        puts "Hello"
    end
    
    twice { puts "hello" }

    twice 方法传入 block 也非常简单,使用 doend 或者 {} 就可以向任何的 Ruby 方法中传入代码块。

    eval

    早在几十年前的 Lisp 语言就有了 eval 这个方法,这个方法会将字符串当做代码来执行,也就是说 eval 模糊了代码与数据之间的边界。

    > eval "1 + 2 * 3"
     => 7

    有了 eval 方法,我们就获得了更加强大的动态能力,在运行时,使用字符串来改变控制流程,执行代码并可以直接利用当前语言的解释器;而不需要去手动解析字符串然后执行代码。

    格式和约定

    编写 Ruby 脚本时并不需要像 Python 一样对代码的格式有着严格的规定,没有对空行、Tab 的要求,完全可以想怎么写就怎么写,这样极大的增加了 DSL 设计的可能性。

    同时,在一般情况下,Ruby 在方法调用时并不需要添加括号:

    puts "Wello World!"
    puts("Hello World!")

    这样减少了 DSL 中的噪音,能够帮助我们更加关心语法以及语义上的设计,降低了使用者出错的可能性。

    最后,Ruby 中存在一种特殊的数据格式 Symbol

    > :symbol.to_s
     => "symbol"
    > "symbol".to_sym
     => :symbol

    Symbol 可以通过 Ruby 中内置的方法与字符串之间无缝转换。那么作为一种字符串的替代品,它的使用也能够降低使用者出错的成本并提升使用体验,我们并不需要去写两边加上引号的字符串,只需要以 : 开头就能创建一个 Symbol 对象。

    Podfile 是什么

    对 Ruby 有了一些了解之后,我们就可以再看一下使用 CocoaPods 的工程中的 Podfile 到底是什么了:

    source 'https://github.com/CocoaPods/Specs.git'
    
    target 'Demo' do
        pod 'Mantle', '~> 1.5.1'
        ...
    end

    如果不了解 iOS 开发后者没有使用过 CocoaPods,笔者在这里简单介绍一下这个文件中的一些信息。

    source 可以看作是存储依赖元信息(包括依赖的对应的 GitHub 地址)的源地址;

    target 表示需要添加依赖的工程的名字;

    pod 表示依赖,Mantle 为依赖的框架,后面是版本号。

    上面是一个使用 Podfile 定义依赖的一个例子,不过 Podfile 对约束的描述其实是这样的:

    source('https://github.com/CocoaPods/Specs.git')
    
    target('Demo') do
        pod('Mantle', '~> 1.5.1')
        ...
    end

    Podfile 中对于约束的描述,其实都可以看作是代码的简写,在解析时会当做 Ruby 代码来执行。

    简单搞个 Embedded DSL

    使用 Ruby 实现嵌入式 DSL 一般需要三个步骤,这里以 CocoaPods 为例进行简单介绍:

    • 创建一个 Podfile 中“代码”执行的上下文,也就是一些方法;

    • 读取 Podfile 中的内容到脚本中;

    • 使用 eval 在上下文中执行 Podfile 中的“代码”;

    原理

    CocoaPods 对于 DSL 的实现基本上就是我们创建一个 DSL 的过程,定义一系列必要的方法,比如 sourcepod 等等,创造一个执行的上下文;然后去读存储 DSL 的文件,并且使用 eval 执行。

    信息的传递一般都是通过参数来进行的,比如:

    source 'https://github.com/CocoaPods/Specs.git'

    source 方法的参数就是依赖元信息 Specs 的 Git 地址,在 eval 执行时就会被读取到 CocoaPods 中,然后进行分析。

    实现

    下面是一个非常常见的 Podfile 内容:

    source 'http://source.git'
    platform :ios, '8.0'
    
    target 'Demo' do
        pod 'AFNetworking'
        pod 'SDWebImage'
        pod 'Masonry'
        pod "Typeset"
        pod 'BlocksKit'
        pod 'Mantle'
        pod 'IQKeyboardManager'
        pod 'IQDropDownTextField'
    end

    因为这里的 sourceplatformtarget 以及 pod 都是方法,所以在这里我们需要构建一个包含上述方法的上下文:

    # eval_pod.rb
    $hash_value = {}
    
    def source(url)
    end
    
    def target(target)
    end
    
    def platform(platform, version)
    end
    
    def pod(pod)
    end

    使用一个全局变量 hash_value 存储 Podfile 中指定的依赖,并且构建了一个 Podfile 解析脚本的骨架;我们先不去完善这些方法的实现细节,先尝试一下读取 Podfile 中的内容并执行 eval 看看会不会有问题。

    eval_pod.rb 文件的最下面加入这几行代码:

    content = File.read './Podfile'
    eval content
    p $hash_value

    这里读取了 Podfile 文件中的内容,并把其中的内容当做字符串执行,最后打印 hash_value 的值。

    $ ruby eval_pod.rb

    运行这段 Ruby 代码虽然并没有什么输出,但是并没有报出任何的错误,接下来我们就可以完善这些方法了:

    def source(url)
        $hash_value['source'] = url
    end
    
    def target(target)
        targets = $hash_value['targets']
        targets = [] if targets == nil
        targets << target
        $hash_value['targets'] = targets
        yield if block_given?
    end
    
    def platform(platform, version)
    end
    
    def pod(pod)
        pods = $hash_value['pods']
        pods = [] if pods == nil
        pods << pod
        $hash_value['pods'] = pods
    end

    在添加了这些方法的实现之后,再次运行脚本就会得到 Podfile 中的依赖信息了,不过这里的实现非常简单的,很多情况都没有处理:

    $ ruby eval_pod.rb
    {"source"=>"http://source.git", "targets"=>["Demo"], "pods"=>["AFNetworking", "SDWebImage", "Masonry", "Typeset", "BlocksKit", "Mantle", "IQKeyboardManager", "IQDropDownTextField"]}

    不过使用 Ruby 构建一个嵌入式 DSL 的过程大概就是这样,使用语言内建的特性来进行创作,创造出一个在使用时看起来并不像代码的 DSL。

    写在后面

    在最后,笔者想说的是,当我们在某一个领域经常需要解决重复性问题时,可以考虑实现一个 DSL 专门用来解决这些类似的问题。

    而使用嵌入式 DSL 来解决这些问题是一个非常好的办法,我们并不需要重新实现解释器,也可以利用宿主语言的抽象能力。

    同时,在嵌入式 DSL 扩展了 DSL 的范畴之后,不要纠结于某些东西到底是框架还是领域特定语言,这些都不重要,重要的是,在遇到了某些问题时,我们能否跳出来,使用文中介绍的方法减轻我们的工作量。

    Reference

    其它

    GitHub Repo:iOS-Source-Code-Analyze

    Follow: Draveness · GitHub

    Source: http://draveness.me/dsl

    展开全文
  • 840DSL操作手册

    2015-08-25 18:15:14
    840DSL是西门子公司推出的一款高端系统,本说明书可以帮助操作人员
  • dsl拨号

    2011-09-04 22:32:48
    租下房子的第二天,便牵了一家不知名的网络公司的宽带, 1.5m, 50/月。觉着还算便宜。网速嘛,马马虎虎,下bt不行, 但是看qq和youku的视频还好。不怎么卡。windows下木有啥问题。linux下却经常的掉线重连。烦恼。...
    长夜漫漫,无心睡眠啊。租下房子的第二天,便牵了一家不知名的网络公司的宽带, 1.5m, 50/月。觉着还算便宜。网速嘛,马马虎虎,下bt不行, 但是看qq和youku的视频还好。不怎么卡。windows下木有啥问题。linux下却经常的掉线重连。烦恼。google之,实践之。最后算是解决了。记录如下。
    [b]1.问题分析[/b]
    使用plog -f命令查看ppop的日志,注意到日志中有下面一句
    Sep 4 22:03:27 aiwen-hust pppd[18245] No response to 3 echo-requests
    由此知道,断掉dsl的原因是程序连续3次没有接受到echo-requests。

    [b]2.解决办法[/b]
    (1).使用pppoeconf命令
    a.配置ppp拨号:sudo pppoeconf, 根据提示输入相应的信息
    b.启动/停止拨号:
    pon dsl-provider
    poff dsl-provider
    c.修改配置 /etc/ppp/peers/dsl-provider,将lcp-echo-failure修改为40,lcp-echo-interval修改为30,然后重启拨号
    (2).使用图形界面
    图形界面使用的配置文件是/etc/ppp/options。修改同样的选项即可。

    [b]3.结果和总结[/b]
    发现。。。这写拨号程序的人真牛叉。后面又断掉了。因为有40个echo-requests没收到。难道错误统计没有时间段设置的?只统计总量?悲催啊。
    展开全文
  • 著名电信业咨询公司Ovum的2010年第二季度宽带接入市场份额统计表显示:该季度DSL全球市场(不包含DSL客户端设备)共收入8.48 亿美元,而 FTTB/FTTH市场(含客户端设备ONUs和ONTs)的收入为7.96亿美元。在过去的两年中,...
  • DCS800 DSL板.pdf

    2019-06-14 17:40:40
    ABB公司DCS800整流器 固件手册册 版本D,中文版,DSL板使用说明。
  • Discovery Future是一家区块链科技创新集团公司,注册地为英属维京群岛。主营区块链技术应用研发,创新互联网软件开发,广告传播技术创新,场景应用数据...Discovery Link发现链,简称DSL。是DSLteam近三十人的区...
  • 840Dsl读取S120电流步骤

    2018-05-19 16:13:57
    公司里经常有人问西门子840d或者840dsl机床伺服电机电流速度怎么读取到PLC,因此想到将自己整理的详细文档及注意事项拿出来分享,希望能对初学者有点指导意义。
  • Dalias公司推出的数字化温度传感器I)S18820的独特的“单线总线”,可以使用户方便地使用多片I)S18820构成多点温度测量系统,因此如何准确、有效地对挂在同一条单线总线上的多片Dsl8820 ROM编码进行搜索与识别成为...
  • TraceSpan Communications公司发布最新的ADSL2+多层分析仪——DSL Xpert 2208。该产品据称为业界唯一适用于ADSL2+、ADSL2和ADSL设备的非插入式性能分析仪,主要面向从事ADSL2+、ADSL2和ADSL标准产品应用的研发、质量...
  • (“Sisvel”)今天宣布,Sisvel与诺基亚公司(“诺基亚”)已签订一份DSL专利许可协议。全世界有越来越多的公司可以使用Sisvel持有的对ITU-T DSL标准至关重要的专利组合,诺基亚现已加入它们的行列。 诺基亚与...
  • 卢森堡--(美国商业资讯)--Sisvel International S.A. (“Sisvel”) 今天宣布Sisvel与 ASUSTeK Computer ...在全球范围内,越来越多的公司获得使用Sisvel所持专利的相关授权,自此ASUS也加入了这一行列。 该协议解决...
  • ###“没有软件是一座孤岛”(谷歌公司) 向 ATOM 添加 4GL OpenEdge 开发支持。 该项目旨在为 Progress 开发人员提供强大而动态的生产力。 安装 您可以从配置面板安装: 文件 -> 设置 -> 安装 -> 搜索“dsl-...
  • antlr, DSL,

    2014-06-14 09:53:39
    讲师:施懿民-上海知平信息技术有限公司创始人 上海知平信息技术有限公司创始人,专注于基于SAAS的CRM和企业管理系统开发。 在创建知平信息技术之前,在文思海辉集团工作多年,主要工作在微软.NET虚拟机CLR...
  • 摘要:详细介绍单总线温度传感器DSl8B20的工作原理、通信协议和使用方法;给出测温程序流程,以及DSl8B20在Proteus中硬件仿真的具体实现方法,并对该仿真结果与实验...Dallas公司推出的单总线技术用单根信号线及地线
  • 昨天下载一个公司的项目,前期各种报错,到最后报了2个错误,特此记录下: 1、ERROR: Gradle DSL method not found: 'google()' 新版本androidstudio版本不在支持google()这种,需要在项目的build.gradle里面把 ...
  • 公司的创新计划中研究的动态网络防御网络安全平台。 规则引擎提供了一种智力,一种人工智能形式,一种对工作记忆进行客观推理和理解的能力。 内存保留了与系统相关的知识,以及在 DSL 中编写的一组规则,这些规则...
  • 最近在学习Ruby的时候,看到Martin Fowler的文章有说,Ruby流行的一个很重要原因是它非常适合用来编写内部领域特定语言(Internal DSL),当时对DSL这个新鲜的名词非常不解,适逢公司有精于此道的大佛,万幸求得了一...
  • 摘要:详细介绍单总线温度传感器DSl8B20的工作原理、通信协议和使用方法;给出测温程序流程,以及DSl8B20在Proteus中硬件仿真的具体实现方法,并对该仿真结果与实验...Dallas公司推出的单总线技术用单根信号线及地线
  • 该产品基于高性能 ARM 网络处理器,集成了该公司广泛部署的数字用户线(DSL)、PRISM? 无线网络和语音处理技术。CX9461x 产品系列针对下一代 DSL 网关、网桥和路由器,可为先进三重服务提供所需的语音、视频和数据...
  • EPCOS公司开发出适用于DSL设备变压器的新型EPX9/9/9磁芯。该器件与Duroplast新开发的SMD线圈架相结合,可提供更多的绕组间隙,采用最先进的宽带铁氧材料T38、T57、T66和N45制成。数字用户线路(DSL)技术是发展最快的...
  • 演化架构和紧急设计: 使用 JRuby 构建 DSL演化架构和紧急设计: 使用 JRuby 构建 DSL通过在 Java 代码之上使用 JRuby 来利用 Ruby 的表现力Neal Ford, 软件架构师/Meme Wrangler, ThoughtWorks Inc.Neal Ford 是一家...
  • 本文介绍利用ACTEL公司的ProASICplus系列FPGA实现与DS18B20的通信功能。FPGA可以将读出DS18B20的48位ID号和12位温度测量结果保存在内部寄存器中,微处理器可以随时快速地从FPGA寄存器中读取这些信息。
  • 微软whql认证代理公司 HTTP://WWW.WHQL-CHINA.COM 中兴通讯多款DSL MODEM通过微软WHQL测试 上海中兴通讯DSL MODEM获得微软WHQL认证证书,联合安信帮助其完成驱动程序安...
  • 该产品基于高性能 ARM:trade_mark: 网络处理器,集成了该公司广泛部署的数字用户线(DSL)、PRISM:registered: 无线网络和语音处理技术。CX9461x 产品系列针对下一代 DSL 网关、网桥和路由器,可为先进三重服务提供所...
  • Epcos公司推出的新款B78416系列小型接口变压器适用于DSL设备。B78416系列小型接口变压器基于EP5XL核,与基于EP7的变压器相比,面积减小25%,达到64.5mm2,高度缩短31%,达到7mm,体积缩小48%,达到451.5m3。B78416A...
  • Domain Specific Language(DSL)感想2

    千次阅读 2007-08-24 22:04:00
    Martin Fowler在我心目中是个大牛,ThoughtWorks公司的chief scientist.每次听他的presentation都很激动,幸亏有了internet这个好玩意,否则我这样一个小小程序员是不可能有机会听他的演讲的。最近他老人家显然一直...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 338
精华内容 135
关键字:

dsl公司