zoukankan      html  css  js  c++  java
  • 测试驱动 ASP.NET MVC Type Aliase

    Type Aliase

    去掉Scala的糖衣(4) -- Type Aliase

    我的新博客地址:http://cuipengfei.me/blog/2013/12/23/desugar-scala-4/

    Scala中有一个type关键字,用来给类型或者是操作起别名,用起来很是方便。

    比如这样:

    1
    
    type People = List[Person]
    

    这样就是给List[Person](方括号是Scala的类型参数的写法)声明了一个别名,叫做People。

    接下来就可以这样使用它:

    1
    2
    3
    
      def teenagers(people: People): People = {
        people.filter(person => person.age < 20)
      }
    

    这个代码编译之后没有什么神奇的,仅仅是把所有出现People这个字眼的地方都用List of Person替代了。

    1
    2
    3
    4
    5
    6
    7
    
      public List<Person> teenagers(List<Person> people)
      {
        return (List)people.filter(new AbstractFunction1() { public static final long serialVersionUID = 0L;
          public final boolean apply(Person person) { return person.age() < 20; }
        });
      }
    

    这种给类型一个别名的特性只是一个小糖豆,不太甜,真正有趣的是给一类操作命名(联想C#中定义delegate)。

    比如这样:

    1
    
    type PersonPredicate = Person => Boolean
    

    接受一个Person,返回一个Boolean,我们把这一类用来判断一个人是否符合某个条件的操作统称为PersonPredicate。

    然后我们可以定义以下predicate:

    1
    
    val teenagerPred: PersonPredicate = person => person.age < 20
    

    然后前面写过的teenagers方法就可以这样重新定义:

    1
    2
    3
    
      def teenagers(people: People): People = {
        people.filter(teenagerPred)
      }
    

    按照这个思路下去,我们就可以开始composite functions了。比如说,我们跟人收税,就可以这么做:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      type Tax = Person => Double
      val incomeTax: Tax = person => person.income * 5 / 100
      val kejuanzaTax: Tax = person => person.income * 20 / 100
      def giveMeYourMoney(p: Person) = {
        calculateTax(p, List(incomeTax, kejuanzaTax))
      }
      def calculateTax(person: Person, taxes: List[Tax]): Double = {
        taxes.foldLeft(0d) {
          (acc, curTax) => acc + curTax(person)
        }
      }
    

    从一个人那里拿到钱,这种操作,我们称之为Tax。然后定义个税和苛捐杂税,或者也可以有任意多的税种。

    然后就可以把任意的几个税种放在一个List里面,和calculateTax去composite了。

    当然,没有type这个关键字,我们也可以composite functions。只不过就得写成这样:

    1
    2
    
    val teenagerPred: (Person) => Boolean = person => person.age < 20
    def incomeTax: (Person) => Double = person => person.income * 5 / 100
    

    看着稍微有点眼花。

    这种用type关键字给一种操作命名的代码反编译之后是这样的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
      public Function1<Person, Object> teenagerPred()
      {
        return new AbstractFunction1() { public static final long serialVersionUID = 0L;
          public final boolean apply(Person person) { return person.age() < 20; }  } ;
      }
      public Function1<Person, Object> incomeTax()
      {
        return new AbstractFunction1() { public static final long serialVersionUID = 0L;
          public final double apply(Person person) { return person.income() * 5 / 100; }  } ;
      }
      public Function1<Person, Object> kejuanzaTax()
      {
          return new AbstractFunction1() { public static final long serialVersionUID = 0L;
        public final double apply(Person person) { return person.income() * 20 / 100; } } ;
      }
    

    可以看到所有这种接受一个参数,返回一个值的操作都是Function1<Person, Object>。

    推测一下,接受两个参数,返回一个值的是不是该叫做Function2呢?

    1
    2
    3
    
    type TwoToOne = (String, Int) => Double
    def twoToOneImpl: TwoToOne = (str, i) => 1
    

    反编译之后,果不其然:

    1
    2
    3
    4
    
    public Function2<String, Object, Object> twoToOneImpl()
    {
      return new Hello..anonfun.twoToOneImpl.1(this);
    }
    

    那不接收参数,只有返回值的呢?

    1
    2
    3
    
      type NoInJustOut = () => String
      def noInJustOutImpl: NoInJustOut = () => "hello world"
    

    反编译之后,其实是变成了Function0 of String:

    1
    2
    3
    4
    
      public Function0<String> noInJustOutImpl()
      {
        return new Hello..anonfun.noInJustOutImpl.1(this);
      }
    

    到这里,我们可以总结一下type alia这个糖衣:

    一个类型的type alias,类似于这样的:type t = x。编译器将在所有使用到t的地方把t替换为x。

    对于一种操作的type alias,编译器将会根据参数列表和返回值类型的不同将其替换为对应的Function0,Function1,Function2 …… 一直到Function22。

    如果我们真的定义一个超过二十二个参数的操作会如何呢?

    1
    2
    3
    4
    5
    6
    7
    8
    
      type twentyThree = (
          String, String, String, String,
          String, String, String, String,
          String, String, String, String,
          String, String, String, String,
          String, String, String, String,
          String, String, String
        ) => String
    

    Scala编译器会直接告诉我们: type Function23 is not a member of package scala

    【测试驱动 ASP.NET MVC】

    http://msdn.microsoft.com/zh-cn/magazine/jj190803.aspx 

    【构建可测试 ASP.NET MVC 应用程序】

    http://msdn.microsoft.com/zh-cn/magazine/dd942838.aspx

    Pragmatic.Test.Drive.ASP.NET.MVC.Jun.2010 
    image
     

    http://vdisk.weibo.com/s/DOlfks4ooGf 【图片可以点击】 

    这本很薄的小书,今年读了至少4边,汤姆大叔翻译的js也看了几遍,受益匪浅

    现在已经完成了60%的代码重构,因为垃圾站很简单,

    虽然现在还没有深入到复杂模块和高难度模块单元测试,但普通的单元测试已经解决了我很多问题了

    1 拖沓,以前写一个模块用老长时间,都是周末或平时有空写写,有时候记不起来几个月前定的需求,就一直放着,等想起来在写

    现在先写完单元测试代码,明确的具体的规则,和目标,每次写之前先运行一次单元测试看哪里还没写,拖沓的毛病得到治疗。

    个人感觉对创业团队更为重要:1防止拖沓 2防止赶工期出垃圾工程

    2长函数,以前也不是有意写长函数,只不过写着写着写着就边长了,我也没办法,

    现在写的时候先要想,我要怎么测试这个东西,复杂的东西不会测,写简单点,好测试

    3成就感,,,,每次看着X号变绿色,心情都好了

    image
  • 相关阅读:
    OWIN katana注册中间件的几种写法
    ASP.NET Identity(处理身份数据存储) 与 OWIN主机(实现katana验证授权)原理概括
    entity framework 查询
    Sencha CMD 4- 安装与首次使用
    比较const ,readonly, stitac readonly
    (二)给IE6-IE9中的input添加HTML5新属性-placeholder
    (一)IE8以下background不起作用
    大虾翻译(一):jQuery.extend()
    JavaScript之三:jQuery插件开发(一)
    《JavaScript DOM编程艺术》
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3500238.html
Copyright © 2011-2022 走看看