精华内容
下载资源
问答
  • 优秀PPT作品欣赏:培训师成长手册幻灯片下载。 本PPT为读书笔记PowerPoint,设计风格以简洁简约风格,幻灯片采用红色主题背景色。 PPT主要内容为教你怎样成为一名优秀的培训师; 培训师成长手册 困惑 ...
  • 优秀PPT作品欣赏:培训师成长手册幻灯片下载。 本PPT为读书笔记PowerPoint,设计风格以简洁简约风格,幻灯片采用红色主题背景色。 PPT主要内容为教你怎样成为一名优秀的培训师; 培训师成长手册 困惑 培训师职业...
  • 4、腾讯游戏:让爱看得见 类型:公益类 时间:2019年9月 理由:非常优秀的美术 在每年的99公益期间,我们都能看到大量H5作品为推广活动上线,而在今年的公益日,让我印象最为深刻的就是这支了。为了表现盲人的内心...

    时间真的过的好快,2019年还有不到2周,就结束了,而在这下半年,究竟有哪些H5作品比较有代表性?又有哪些作品引起了用户和行业的关注?

    这一期,小呆就给你总结其中最有代表性的10个案例,内容如下:

    1、坏打印机:APP屏幕时间数据可视化

    类型:内容类

    时间:2019年6月

    理由:最有技术含量的自发项目

    其实,在H5领域技术与形式的探索方面,还是要通过同行大神的自发项目,才能让我们看到,特别的闪光点与新方向。

    例如,来自公号-坏打印机的,这支数据可视化品牌联盟H5,通过作品3D+2D的视觉呈现方式,让我们看到H5的不同表现力。

    b5b1153c77db53475be6ad5f17287ad0.png

    扫描二维码,立即体验!

    dc110e0827dcfe2f892dca3610a420fb.png

    2、腾讯新闻:垃圾分类大挑战

    类型:新闻类

    时间:2019年7月

    理由:快速解读社会热点

    今年夏天,超出所有人意料:垃圾分裂,利国利民,这样一个社会共识,居然成了全民槽点,大家对一刀切的执行方式,展开了各种花式吐槽,把垃圾分类送上了热搜的NO.1!

    而在这一时期,朋友圈也出现大量主题H5,在其中,传播最广、立意最鲜明、上线最快、互动方式最有趣的就是腾讯这支H5了。同样是跟热点,它就做到了快、准、狠,通过游戏互动来体现,大部分人分不清各种垃圾类型的痛点。案例深度分析文章:除了上海,据说垃圾分类要普及全国了!

    7d1b3f2ee9aaff0fbaa7c0441a51cf85.png

    扫描二维码,立即体验!

    0a1ea18e58b29d6267a14076bc1627eb.png

    3、脉脉:蓝月

    类型:内容类


    时间:2019年8月


    理由:今年最有质量的互动电影

    上线最初遭到吐槽,但很快形成口碑逆袭,并引起广告圈、互联网圈、影视圈与H5行业圈的集体围观。除直接关注外,作品还为脉脉带来了大量意想不到的后期合作机会,甚至包括拍摄系列互动剧的合作请求。

    这一系列的反馈,都让我们看到了,深度互动类内容所带来的爆发力,这确实是一个值得深耕的未来机会,而没想到的是,抓住这个机会的居然是一家做职场产品的甲方单位,意不意外呀?

    83dffadf710fd240a9801b69f6522ddc.png

    扫描二维码,立即体验!

    2b46e1e94b17cca35237d747c3cecd45.png

    4、腾讯游戏:让爱看得见

    类型:公益类


    时间:2019年9月


    理由:非常优秀的美术

    在每年的99公益期间,我们都能看到大量H5作品为推广活动上线,而在今年的公益日,让我印象最为深刻的就是这支了。为了表现盲人的内心世界,作品通过大量的视觉幻想和构思,描述了一个绚丽多彩的奇幻境遇。

    观看H5,就好比是一次心灵的进化过程,这样的作品,难道不值得收藏么?案例深度分析文章:《视觉设计,美到能进化心灵!》

    845273ca573b75774a270aafb0714d2e.png

    扫描二维码,立即体验!

    151577a3cb985f8ec7648f5da1042706.png

    5、腾讯新闻:迎国庆换新颜

    类型:新闻类


    时间:2019年10月


    理由:年度最火爆

    在今年国庆期间,小站做了专题总结,发现H5案例总数至少超过了40支,而在这其中,最受欢迎,转发量最大的,就是这支了!就火爆程度而言,说这支H5,是2019年最为火爆的案例,都觉得毫不夸张。

    不得不说,腾讯新闻在H5的设计上,确实有两把刷子,每次都是又快又准,凭借这支H5的刷屏,小站也第一次刷出了一篇10W+的文章:《教你,如何获得@国旗微信头像!(内置教程)》。

    300ff5ba186cf1719135cd4809b38103.png

    扫描二维码,立即体验!

    060e760051b0f72bd817a3bd4e39b63b.png

    6、腾讯:腾讯ME医学大会

    类型:营销类

    时间:2019年10月


    理由:技术表现力非常强

    可以说,这支是今年我们见到的,在技术表现与美术设计方面,结合的最出色的H5商业案例作品了。

    医疗主题与3D表现形式这两个事物,一个是需求方向,一个是制作方式,都是H5领域很少出现的,而这样的一个组合,必将成就一支经典作品。案例深度分析文章:《真的!2020年都不见得有颜值这么高的H5》

    cd02412a928057da6269ad939e7e87aa.png

    扫描二维码,立即体验!

    09253266ac1e15a995a271933f9dbfbb.png

    7、淘宝:淘宝人生账单

    类型:营销类


    时间:2019年11月


    理由:关注度极高的大数据报告

    在手机淘宝,输入“看鬼故事”或者输入“淘宝人生账单”,你都会看到这份你在淘宝的消费总清单,在今年双11后,这样的一支淘宝H5,成为了热搜内容,关注度极高。

    原则上来说,微信和淘宝的一些底层数据是可打通的,但现实情况是,这是根本不可能的事情!所以,就硬生生的分化出了淘宝H5与微信H5,这两个不同的领域。

    b6cfd91acd7ffc32e7cf6e070ad88a1c.png

    8、网易新闻:专属小诗

    类型:内容类


    时间:2019年11月


    理由:互动性很强的情感小测试

    这支H5,就非常类似,网易新闻上半年上线的《饲养手册》,不同的是,更换了主题和美术形式,而内容与架构,可以说是完全一致的。制作上非常的精良,尤其是很多小细节的设计都非常的精致,而这支H5的命运也和《饲养手册》一样,被永久封杀了链接。

    所以说,如果想观看这支H5的话,再长按识别二维码后,要选择浏览器打开,才可以观看。

    a364c3a89e28acca7fcb014832c281dd.png

    扫描二维码,立即体验!

    733c04e20750816b06e9fd24ff2f2917.png

    9、数英网:2019-赞赞赞赞赞赞

    类型:内容类


    时间:2019年12月


    理由:营销人自己的H5

    数英网的这个积赞系列,是从2018年开始的,这次H5是该系列第二季。

    H5、短片、刷屏广告的制作都是由谁完成的?当然是,那些散落在各大城市的制作团队了,作为幕后人物,这个系列的H5首次将他们推到了台前,让大家能够看到他们,感受到他们的存在。可以说,这样的作品,是可以为辛劳的同行们发声的一个窗口呀。

    b301d5ed600cc333b5f52173fbea5ac7.png

    扫描二维码,立即体验!

    8913d91c12d1c282f968b8d22da0c254.png

    10、未知:2020年会发生的几件事

    类型:内容类


    时间:2019年12月


    理由:套路刷屏模范作品

    这几乎成为了每年必刷屏的H5作品系列了,而情况也惊人的相似:形式简单、必有年度总结、出品方未知、必然刷屏后被封。从每年年度总结类H5刷屏的现象,我们也能看出,H5想要获得传播的一些基本共识性特征,例如:一定的是普遍性话题,才有可能获得大规模传播这样的特征。

    f42bc4c0d6483df13f09eda4c6e48653.png

    你应该也发现了,下半年,H5的热度明显变小了,究其原因,我觉得可能是以下几点:

    1、现在的数字营销的投放方式变多样了,尤其是小视频的崛起,一定程度的分流了很多H5的需求和流量。

    2、今年随着大环境的变化,不止是H5,相关的数字内容推广都有不小的萎缩。

    3、微信对H5的限制更加多了,很多制作人感慨的就是这个,不是我没有好的创意,不是我没有能力刷屏,或者做爆款,是你TM限制我不让我做,看着TX本家的H5刷的那个猛烈,我就很难受,他娘的,这不是欺

    负人么...

    07dfebc846ec71cc74761690af101405.png

    这也是为啥,淘宝类H5在今年会给人的整体要好的多,虽然制作起来流程非常繁琐,虽然,淘宝APP没有微信的用户广场,但大促期间的淘宝H5真的有非常好的转化和传播,简直吊打微信H5,就是这个样子,木有办法。

    各路第三方品牌和公司,多年来在微信做H5,玩出了名堂和方法,然后被微信吸取了精华,将他们都应用在了自己的原生朋友圈广告,然后,再开始限制各种所谓的“外链”。这就是一盘大棋,这就是讲话,朋友们,想想都是泪呀,有点难受。

    这就是小站2019年下半年的年度作品分析了,近期,小呆还会为你更新,2019年H5的全年总结报告,可千万别错过了!

    原创作者/公号:小呆

    著作权归作者所有,本站根据CC0协议授权转发

    商业转载请联系作者获得授权,非商业转载请注明出处

    联系:[运营的小事]编辑

    展开全文
  • 优秀的 HTML5 网站设计案例欣赏

    千次阅读 2019-06-15 12:09:35
    原文:12个优秀的 HTML5 网站设计案例欣赏HTML5网站相关文章   15个精美的 HTML5 单页网站作品欣赏 10个很酷的 HTML5 字体应用演示网站 10个精美的 HTML...
    展开全文
  • Kotlin 作为后起之秀,站在巨人们的肩膀上是她得天独厚的优势,而这个巨人也包括—《Effective Java》(EJ),得益于这个巨人,Kotlin 到处散发着高效的味道,这文章让我们一起来领略下 Kotlin 的高效之道。...

    Kotlin 作为后起之秀,站在巨人们的肩膀上是她得天独厚的优势,而这个巨人也包括—《Effective Java》(EJ),得益于这个巨人,Kotlin 到处散发着高效的味道,这篇文章让我们一起来领略下 Kotlin 的高效之道。

    EJ 第1条:考虑使用静态工厂方法代替构造器

    在实例化对象的方式中,使用静态工厂方法相比构造器有几个好处:

    1. 工厂方法拥有名字,易于开发者理解。

    2. 不必在每次调用的时候都创建一个新对象,比如可以事先缓存好实例。

    3. 可以返回原类型的任何子类型。

    Kotlin 并没有 static 关键字,也没有静态成员的概念,取而代之的是『伴生对象』,因此,对于第一条准则,Kotlin 使用伴生对象关键字 companion 来定义静态工厂方法,代码风格如下:

    class User private constructor(val account:String){
    
        companion object {
    
            fun newWeiboUser(email:String):User{
                return User(email)
            }
    
            fun newTelUser(tel:Long):User{
                return User(tel.toString())
            }
        }
    
    }
    
    

    调用方式类似 Java 中的静态方法:

    val newTelUser = User.newTelUser(18888888888)
    val weiBoUser = User.newWeiboUser("geniusmart")
    
    

    EJ 第3条:用私有构造器或者枚举类型强化Singleton属性

    对于开发者而言,单例模式是最耳熟能详的设计模式,正如这第3条准则所述,单例模式有懒汉式、饿汉式、枚举等多种写法,其中前两者我们必须用私有构造器来禁止在单例之外的实例化。

    Kotlin 对单例模式做了更彻底的精简,简直易如反掌,可以通过 object 关键字声明一个单例类的同时创建一个实例,如:

    object singleton{//由于同时创建了实例,因此类名使用小写
        fun action(){
            println(this.hashCode())
        }
    }
    
    

    简单验证如下:

    @Test
    fun test(){
         val instance1 = singleton
         val instance2 = singleton
         assertEquals(instance1,instance2)
    }
    
    

    如果将 object singleton 转换成 Java,代码如下,大家可以感受下如何在声明一个单例类的同时创建一个实例:

    public final class singleton {
       //在Java中使用singleton.INSTANCE来访问单例
       public static final singleton INSTANCE;
       private singleton() {
          INSTANCE = (singleton)this;
       }
    
       static {
          new singleton();
       }
    }
    
    

    Kotlin 让创建单例变得更高效。

    EJ 第13条:使类和成员的可访问性最小化

    封装(也称之为信息隐藏)是面向对象的四大特性之一,体现在具体的实现层面便是四种访问权限:private、default、protected 和 public

    面向对象编程,我们的代码充满着类、成员属性和成员方法,这些都是我们对外的契约,如果类和成员都是可访问的,意味着我们后续的迭代版本都必须保持兼容,这显然是一项巨大的工程。

    反之,充分利用好四种访问权限,将类和成员的可访问性控制到最小,更有利于程序的扩展。在这点上,Java 和 Kotlin 是大体一致的,但有细微区别:

    1. Kotlin 的默认访问权限为 public

    2. Kotlin 没有包级别访问权限。因为 Kotlin 认为包级别的访问权限很容易被破坏:只要使用者创建一个一模一样的包名即可访问,取代方案参照下一点。

    3. Kotlin 新增了模块可见的访问权限 internal

    4. Kotlin 新增了顶层声明的类别(顶层函数和顶层属性,无需放在类中的属性和方法)。

    关于 internal,举个栗子:假设工程里有两个 module,app 和 lib,app 依赖于 lib 工程,代码层级如下:

    app
    -- class Activity
    lib
    -- internal class StringUtils
    

    StringUtils 仅在 lib 工程中可视,app 工程中的 Activity 无法访问该类。

    Kotlin 在访问权限的设计更彻底的贯彻了使可访问性最小化的准则。

    EJ 第14条:在公有类中使用访问方法而非公有域

    public class Point {
        public double x;
        public double y;
    }
    
    

    如上代码,我们会直接调用 public 修饰的成员属性(即准则中的公有域),《Effective Java》 不建议这么用,取而代之的是将成员属性定义成私有的,并且提供 public 修饰的 set 和 get 方法。

    原因很简单:如果直接暴露成员属性,将来想改变其内部实现是不可能的,反之,如果是暴露方法,则可以在方法中轻易地修改实现。

    对于这条准则,Kotlin 在语法层面直接默认约束了:

    class User{
        val num = 10//属性默认为private,且拥有public的getNum()
        var nickname = "geniusmart"//同上
    }
    
    

    调用属性的时候,看似直接访问,实则访问的是 get 和 set 方法:

    @Test
    fun test(){
        val user = User()
        println(user.num)//实际上调用的是getNum()
        user.nickname = "Mr.Geniusmart"//实际上调用的是setNum()
        println(user.nickname)
    }
    
    

    如果哪一天,业务需要我们将所有昵称带上邮箱,此时亡羊补牢显得轻而易举:

    class User{
    
        val num = 10
        var nickname = "geniusmart"
            get() = field.plus("@email.com")
    
    }
    
    

    Kotlin 的 setter 和 getter 规约完美吻合第14条准则。

    EJ 第16条:组合优先于继承(原书是复合优先于继承)

    组合优先于继承 是面向对象中非常重要的原则之一。继承破坏了封装性,父类必须暴露更多的细节让子类知道(比如使用 protected 访问权限),同时子类依赖于父类的实现,一旦父类改变,子类都会受影响。

    举例说明,我们想对 HashSet 增加『计算新增元素个数』的能力,经过多年面向对象的熏陶,我们信誓旦旦的采用继承的方式:定义 HashSet 的子类,在子类中进行扩展:

    class CountingSet: HashSet<String>() {
    
        var count = 0
    
        override fun add(element: String): Boolean {
            count++
            return super.add(element)
        }
    
        override fun addAll(elements: Collection<String>): Boolean {
            count+=elements.size
            return super.addAll(elements)
        }
    }
    
    

    然而事与愿违的是,父类的 addAll() 将会循环调用 add(),因此,计数器会成倍的增加计数,测试代码如下:

    @Test
    fun test(){
    
       val countingSet = CountingSet()
       countingSet.addAll(setOf("1","2","3"))
       println("countingSet.count=${countingSet.count}")//期望是3,实际上是6
    
    }
    
    

    这个例子告诉我们,继承是多么不可靠,子类与父类的耦合度太强,需要了解太多父类的实现。

    『继承』不是最优解,相较而言,『组合』在这种场景下是更可靠的解决方案:

    class CountintSetComposite(val countingSet : HashSet<String> ){
    
        var count = 0
    
        fun contains(element: String) {
            countingSet.contains(element)
        }
    
        fun add(element: String): Boolean {
            count++
            return countingSet.add(element)
        }
    
        // 庞大的工作量:声明HashSet的所有方法。。
    }
    
    

    但是,这里最大的问题在于:我们必须将父类的所有方法都声明一遍,仅仅是为了扩展其中两个方法 add 和 addAll。

    Kotlin 再次体现了其追求高效的本质,『类委托』是 Kotlin 用来简化『组合』的利器:

    class CountingSetBy(val countingSet: MutableCollection<String>):MutableCollection<String> by countingSet{
    
        var count = 0
    
        override fun add(element: String): Boolean {
            count++
            return countingSet.add(element)
        }
    
        override fun addAll(elements: Collection<String>): Boolean {
            count+=elements.size
            return countingSet.addAll(elements)
        }
    }
    
    

    此例中,MutableCollection(在 Kotlin 中作为 HashSet 的父接口)将其实现委托给 countingSet,我们只需要专注于需要扩展的方法即可。

    注:准确来说,组合更多的目的是增加原始对象的能力,因此是『装饰』而非『代理』,而 Kotlin 的委托类在字面意思上更多的还是体现『代理』的味道。

    EJ 第17条:要么为继承而设计,并提供文档说明,要么就禁止继承

    继承的缺点我们已经在上条准则领略到了,更进一步地,接下来这条准则告诉我们:如没有必要提供继承,则禁止。那么如何来禁止继承?其实很简单,将类定义为 final 类,退而求其次,如果类允许继承,则定义不允许重写的方法为 final 方法。

    既然这是个更好的实践,为什么将其作为默认设计?Kotlin 便是这个思路的践行者,Kotlin 中创建的类和方法默认都是 final 的:

    class Parent{
        fun action(){
    
        }
    }
    
    /*
    // 等价于:
    public final class Parent {
       public final void action() {
       }
    }
    */
    
    

    如果经过深思熟虑,一定要提供继承和重写,则对类或方法增加 open 修饰符即可。

    EJ 第21条:用函数对象表示策略

    关于这条准则,我们从策略模式讲起:

     

    以 Java 的思维模式而言,首先要定义策略接口,及具体的策略实现类:

    interface Strategy{
        fun action()
    }
    
    class StrategyA : Strategy{
        override fun action() {
            println("StrategyA")
        }
    }
    
    class StrategyB : Strategy{
        override fun action() {
            println("StrategyB")
        }
    }
    
    class Context(var strategy: Strategy){
    
        fun preform(){
            strategy.action()
        }
    }
    
    

    使用策略的代码如下:

    val context1 = Context(StrategyA())
    val context2 = Context(StrategyB())
    val context3 = Context(object : Strategy{
        override fun action() {
            println("匿名内部类--StrategyC")
        }
    
    })
    context1.preform()
    
    

    这些代码如同我们两点一线的工作一般毫无新意,Kotlin 的 lambda 表达式则激发了我们内心的一点涟漪:

    class ContextKotlin{
    
        fun perform(strategy: ()->Unit){
            strategy()
        }
    }
    
    @Test
    fun testAdavance(){
        val context = ContextKotlin()
        context.perform {
            println("StrategyA")
        }
        val strategyB = { println("strategyB")}
        context.perform(strategyB)
    }
    
    

    『用函数对象表示策略』,Kotlin 诠释得如此淋漓尽致。

    EJ 第22条:优先考虑静态成员类

    在 Java 中,我们经常要把一个类定义在另外一个类的内部,该类被称之为内部类。内部类有四种:静态成员类、非静态成员类、匿名类和局部类。

    该条款建议优先考虑静态成员类,原因在于静态成员类相比非静态成员类而言,不会持有外部类的引用,会带来几个好处:

    1. 无需实例外部类就可以使用

    2. 当外部类可以被垃圾回收时,不会因为内部类的持有而导致内存泄露。

    Kotlin 在语法层面直接对该条款进行支持,静态成员类在 Kotlin 中称为『嵌套类』,默认的内部类便是嵌套类,比如:

    class Outer {
    
        class Inner { // 默认便是静态成员类,等价于public static final class Inner
    
        }
    }
    
    

    这种『默认的规约』可以减少不必要的非静态成员类,当然如果经过深思熟虑,一定要使用非静态成员类,可以通过 inner 关键字来实现:

    class Outer{
    
        class Inner{ // 静态成员类,等价于public final class Outer
    
        }
    
        inner class OtherInner{ // 非静态成员类
    
            fun action(){
                // 调用外部类实例
                this@Outer.toString()
            }
        }
    }
    
    

    EJ 第36条:坚持使用 Override 注解

    回顾上文提到的具备计数能力的 HashSet,采用继承的方式时,需要对 add 方法进行重写:

    class CountingSet: HashSet<Any>() {
    
        var count = 0
    
        //1.正确的重写
        /*
        override fun add(element: Any): Boolean {
            count++
            return super.add(element)
        }
        */
    
        //2.错误的重写
        fun add(element: Int): Boolean {
            count++
            return super.add(element)
        }
    
    }
    
    

    看上文的第2个 add 方法,实际是重载而非重写,与我们的本意背道而驰,如果对该方法加上 override 注解 ,编译器将提示我们问题所在,从而避免不必要的程序 bug。

    Kotlin 同样是这条准则的兢兢业业的践行者,因为在 Kotlin 中重写方法,必须必须必须强制加上 override

    Kotlin 与 《Effective Java》相映成辉,显得美不胜收。对照《Effective Java》,我们能更好地理解 Kotlin 的诸多语法的设计初衷。

    理解 DSL

    DSL(domain specific language),即领域专用语言:专门解决某一特定问题的计算机语言,比如大家耳熟能详的 SQL 和正则表达式。

    Kotlin DSL 把 Kotlin 的语法糖演绎得淋漓尽致,这些语法糖可谓好吃、好看又好玩,但是,仅痴迷于语法糖只会对语言的理解游离于表面,了解其实现原理,是我们阅读优秀源码、设计整洁代码和理解编程语言的必经之路,本文我们通过 DSL 来感受 Kotlin 之美。

    通用编程语言 vs DSL

    通用编程语言(如 Java、Kotlin、Android等),往往提供了全面的库来帮助开发者开发完整的应用程序,而 DSL 只专注于某个领域,比如 SQL 仅支持数据库的相关处理,而正则表达式只用来检索和替换文本,我们无法用 SQL 或者正则表达式来开发一个完整的应用。

    API vs DSL

    无论是通用编程语言,还是领域专用语言,最终都是要通过 API 的形式向开发者呈现。良好的、优雅的、整洁的、一致的 API 风格是每个优秀开发者的追求,而 DSL 往往具备独特的代码结构和一致的代码风格,从 SQL 和正则表达式的语法风格便可感受一二。

    下文我们也将提到,Kotlin 构建的 DSL,代码风格更具表现力和想象力,也更加优雅。

    内部 DSL

    但是,如果为解决某一特定领域问题就创建一套独立的语言,开发成本和学习成本都很高,因此便有了内部 DSL 的概念。所谓内部 DSL,便是使用通用编程语言来构建 DSL。比如,本文提到的 Kotlin DSL,我们为 Kotlin DSL 做一个简单的定义:

    “使用 Kotlin 语言开发的,解决特定领域问题,具备独特代码结构的 API 。”

    下面,我们就来领略下千变万化的 Kotlin DSL 。

    有趣的 Kotlin DSL

    如果说 Kotlin 是一位魔术师,那么 DSL 便是其赖以成名,令人啧啧称赞的魔术作品,我们先来看下 Kotlin 在各个特定领域的有趣实现。

    1. 日期

    val yesterday = 1.days.ago // 也可以这样写:val yesterday = 1 days ago
    val twoMonthsLater = 2 months fromNow
    
    

    以上日期处理的代码,真正做到见名知意,深谙代码整洁之道,更多细节可参考此库:kxdate 。

    如果不考虑规范,基于该库的设计思路,我们甚至可以设计出如下的 api:

    val yesterday = 1 天 前
    val twoMonthsLater = 2 月 后
    
    

    这个日期处理领域的 DSL 体现出来的代码结构是链式的,并且近似于我们日常使用的英语

    1. 单元测试

    val str = "kotlin"
    str should startWith("kot")
    str.length shouldBe 6
    
    

    与上述日期库的 api 风格类似,该单元测试的代码也是赏心悦目,更多细节可参考此库:kotlintest 。

    基于该库的设计思路,我们甚至可以实现如下的代码风格,如同写英语句子一般简洁:

    "kotlin" should start with "kot"
    "kotlin" should have substring "otl"
    
    

    这个 DSL 的代码结构近似于我们日常使用的英语。

    1. HTML 构建器

    fun createTable() =
        table{
            tr{
                td{
    
                }
            }
        }
    
    >>> println(createTable())
    <table><tr><td></td></tr></table>
    
    

    这个 DSL 的代码结构使用了 lambda 嵌套,并且语义清晰,一目了然。更多详情参考此库:kotlinx.html。

    1. SQL

    (Users innerJoin Cities).slice(Users.name, Cities.name).
                select {(Users.id.eq("andrey") or Users.name.eq("Sergey")) and
                        Users.id.eq("sergey") and Users.cityId.eq(Cities.id)}.forEach {
                println("${it[Users.name]} lives in ${it[Cities.name]}")
            }
    
    

    这类 SQL api 的风格,如果有用过 ORM 的框架,如 ActiveAndroid 或者 Realm 就不会陌生。以上代码来自于此库:Exposed 。

    1. Android 布局

    Anko Layouts 是一套帮助我们更简洁的开发和复用 Android 布局的 DSL ,它的代码风格如下:

    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
    
            super.onCreate(savedInstanceState)
            verticalLayout {
                val name = editText()
                button("Say Hello") {
                    onClick { toast("Hello, ${name.text}!") }
                }
            }
    
        }
    
    }
    
    

    相比于笨重的 XML 布局方式,Anko DSL 显然是更先进和更高效的解决方案。

    1. Gradle 构建

    Gradle 的构建脚本是 groovy,对 Android 程序员有一定的学习成本,目前,Gradle 官方也提供了基于 Kotlin 的构建脚本:Gradle Kotlin DSL , 并提供了类 groovy 的代码风格:

    dependencies {
        compile("com.android.support:appcompat-v7:27.0.1")
        compile("com.android.support.constraint:constraint-layout:1.0.2")
    }
    
    

    完整代码请参考:build.gradle.kts。

    综上,Kotlin DSL 所体现的代码结构有如下特点:链式调用,大括号嵌套,并且可以近似于英语句子。

    实现原理

    看了那么多 Kotlin DSL 的风格和使用场景,相较于刻板的、传统的 Java 而言,更加神奇和富有想象力。要理解 Kotlin DSL 这场魔术盛宴,就必须了解其背后用到的魔术道具——扩展函数、lambda、中缀调用和 invoke 约定。

    扩展函数(扩展属性)

    对于同样作为静态语言的 Kotlin 来说,扩展函数(扩展属性)是让他拥有类似于动态语言能力的法宝,即我们可以为任意对象动态的增加函数或属性。

    比如,为 String 扩展一个函数: lastChar():

    package strings
    
    fun String.lastChar(): Char = this.get(this.length - 1)
    
    

    调用扩展函数:

    >>> println("Kotlin".lastChar())
    n
    
    

    与 JavaScript 这类动态语言不一样,Kotlin 实现原理是:提供静态工具类,将接收对象(此例为 String )做为参数传递进来,以下为该扩展函数编译成 Java 的代码

    /* Java */
    char c = StringUtilKt.lastChar("Java");
    
    

    回顾前文讲到的日期的 DSL:

    val yesterday = 1.days.ago
    
    

    为配合扩展函数,我们先降低 api 的整洁程度,先实现一个扩展函数的版本:

    val yesterday = 1.days().ago()
    
    

    1 为 Int 类型,显然 Int 并没有 days() 函数,因此days() 为扩展函数,伪代码如下:

    fun Int.days() = {//逻辑实现}
    
    

    结合 Java8 的 Time api,此处将会涉及到两个扩展函数,完整实现如下:

    fun Int.days() = Period.ofDays(this)
    fun Period.ago() = LocalDate.now() - this
    
    

    若要实现最终的效果,实际上就是将扩展函数修改为扩展属性的方式即可(扩展属性需提供getter或setter,本质上等同于扩展函数):

    val Int.days:Period
        get() = Period.ofDays(this)
    
    val Period.ago:LocalDate
        get() = LocalDate.now() - this
    
    

    代码虽少,却天马行空,妙趣横生。

    lambda

    lambda 为 Java8 提供的新特性,于2014年3月18日发布。在2018年的今天我们依然无法使用或者要花很大的代价才能在 Android 编程中使用,而 Kotlin 则帮助我们解决了这一瓶颈,这也是我们拥抱 Kotlin 的原因之一。

    lambda 是构建整洁代码的一大利器。

    1. lambda 表达式

    下图是 lambda 表达式,他总是用一对大括号包装起来,可以作为值传递给下节要提到的高阶函数。

     

     

    2. 高阶函数

    关于高阶函数的定义,参考《Kotlin 实战》:

    高阶函数就是以另一个函数作为参数或返回值的函数

    如果用 lamba 来作为高价函数的参数(此时为形参),就必须先了解如何声明一个函数的形参类型,如下:

     

     

    相对于上一小节,我们应该弄清楚 lambda 作为实参和形参时的表现形式:

    // printSum 为高阶函数,定义了 lambda 形参
    fun printSum(sum:(Int,Int)->Int){
            val result = sum(1, 2)
            println(result)
    }
    
    // 以下 lambda 为实参,传递给高阶函数 printSum
    val sum = {x:Int,y:Int->x+y}
    printSum(sum)
    
    

    有了高阶函数,我们可以很轻易地做到一个 lambda 嵌套另一个 lambda 的代码结构。

    3. 大括号放在最后

    Kotlin 的 lambda 有个规约:如果 lambda 表达式是函数的最后一个实参,则可以放在括号外面,并且可以省略括号,如:

    person.maxBy({ p:Person -> p.age })
    
    // 可以写成
    person.maxBy(){
        p:Person -> p.age
    }
    
    // 更简洁的风格:
    person.maxBy{
        p:Person -> p.age
    }
    
    

    这个规约是 Kotlin DSL 实现嵌套结构的本质原因,比如上文提到的 anko Layout:

    verticalLayout {
                val name = editText()
                button("Say Hello") {
                    onClick { toast("Hello, ${name.text}!") }
                }
            }
    
    

    这里 verticalLayout 中 嵌套了 button,想必该库定义了如下函数:

    fun verticalLayout( ()->Unit ){
    
    }
    
    fun button( text:String,()->Unit ){
    
    }
    
    

    verticalLayout 和 button 均是高阶函数,结合大括号放在最后的规约,就形成了 lambda 嵌套的语法结构。

    4. 带接收者的 lambda

    lambda 作为形参函数声明时,可以携带接收者,如下图:

     

     

    带接收者的 lambda 丰富了函数声明的信息,当传递该 lambda值时,将携带该接收者,比如:

    // 声明接收者
    fun kotlinDSL(block:StringBuilder.()->Unit){
      block(StringBuilder("Kotlin"))
    }
    
    // 调用高阶函数
    kotlinDSL {
      // 这个 lambda 的接收者类型为StringBuilder
      append(" DSL")
      println(this)
    }
    
    >>> 输出 Kotlin DSL
    
    

    总而言之,lambda 在 Kotlin 和 Kotlin DSL 中扮演着很重要的角色,是实现整洁代码的必备语法糖。

    中缀调用

    Kotlin 中有种特殊的函数可以使用中缀调用,代码风格如下:

    "key" to "value"
    
    // 等价于
    "key.to("value")
    
    

    而 to() 的实现源码如下:

    infix fun Any.to(that:Any) = Pair(this,that)
    
    

    这段源码理解起来不难,infix 修饰符代表该函数支持中缀调用,然后为任意对象提供扩展函数 to,接受任意对象作为参数,最终返回键值对。

    回顾下我们上文提到的不太规范的中文 api:

    val yesteraty = 1 天 前
    
    

    使用扩展函数和中缀调用便可实现:

    object 前
    infix fun Int.天(ago:前) = LocalDate.now() - Period.ofDays(this)
    
    

    再比如上文提到的:

    "kotlin" should start with "kot"
    
    // 等价于
    "kotlin".should(start).with("kot")
    
    

    使用两个中缀调用便可实现,以下是伪代码:

    object start
    infix fun String.should(start:start):String = ""
    infix fun String.with(str:String):String = ""
    
    

    所以,中缀调用是实现类似英语句子结构 DSL 的核心。

    invoke 约定

    Kotlin 提供了 invoke 约定,可以让对象向函数一样直接调用,比如:

    class Person(val name:String){
        operator fun invoke(){
            println("my name is $name")
        }
    }
    
    >>>val person = Person("geniusmart")
    >>> person()
    my name is geniusmart
    
    

    回顾上文提到的 Gradle Kotlin DSL:

    dependencies {
        compile("com.android.support:appcompat-v7:27.0.1")
        compile("com.android.support.constraint:constraint-layout:1.0.2")
    }
    
    // 等价于:
    dependencies.compile("com.android.support:appcompat-v7:27.0.1")
    dependencies.compile("com.android.support.constraint:constraint-layout:1.0.2")
    
    

    这里,dependencies 是一个实例,既可以调用成员函数 compile,同时也可以直接传递 lambda 参数,后者便是采用了 invoke 约定,实现原理简化如下:

    class Dependencies{
    
        fun compile(coordinate:String){
            println("add $coordinate")
        }
    
        operator fun invoke(block:Dependencies.()->Unit){
            block()
        }
    }
    
    >>>val dependencies = Dependencies()
    >>>// 以两种方式分别调用 compile()
    
    

    invoke 约定让对象调用函数的语法结构更加简洁。

    总结

    细细品味 Kotlin,你会发现她将代码整洁之道(Clean Code)和高效 Java 编程(Effective Java)中的部分精华融入到的语法和默认的规约中,因此她可以让开发者无形中写出整洁和高效的代码。

    而更进一步, Kotlin DSL 则是对 Kotlin 所有语法糖的一个大融合,她的代码结构通常是链式调用、lambda 嵌套,并且接近于日常使用的英语句子,我们可以愉悦的使用 DSL 风格的 API,同时,也可以以此为思路,为社区贡献各种 Kotlin DSL。

    Kotlin DSL 体现了代码的整洁之道,体现了天马行空的想象力,在 DSL 的点缀下,Kotlin 显示出整洁的美,自由的美。

    Kotlin 有趣的外表之下,是一个更有趣的灵魂。

    参考文章

    • 《Effective Java 中文版第2版》

    • 《Kotlin 实战》

    原文:https://www.jianshu.com/p/f5f0d38e3e44


    Kotlin 开发者社区

    国内第一Kotlin 开发者社区公众号,主要分享、交流 Kotlin 编程语言、Spring Boot、Android、React.js/Node.js、函数式编程、编程思想等相关主题。

    展开全文
  • word精美作品合集

    2012-11-06 16:20:55
    word 8word精美文档,部分来源于网络,部分自己做的。
  • 字体原来也可以设计得这么,真是不可思议,一起欣赏吧。 Computer Arts Magazineby Steven Bonner Tangled Handmade Fontby Katya Belkina Typo Graphic Designby Andrei D. Robu Peace by Piece Fo.....

      这篇文章和大家分享40幅非常精美的字体艺术作品。字体原来也可以设计得这么美,真是不可思议,一起欣赏吧。


    Computer Arts Magazine by Steven Bonner

    40幅非常精美的字体艺术作品欣赏

    Tangled Handmade Font by Katya Belkina

    40幅非常精美的字体艺术作品欣赏

    Typo Graphic Design by Andrei D. Robu

    40幅非常精美的字体艺术作品欣赏

    Peace by Piece Font by Scott Wheeler

    40幅非常精美的字体艺术作品欣赏

    El Súper Cartel by Alexander Wright

    40幅非常精美的字体艺术作品欣赏

    40幅非常精美的字体艺术作品欣赏

    Typo Graphic by Marta Podkowinska

    40幅非常精美的字体艺术作品欣赏

    BsAs by Jorge Lawerta

    40幅非常精美的字体艺术作品欣赏

    Ampersand Living Typography by Jason Perez

    40幅非常精美的字体艺术作品欣赏

    Graffiti Style by Andrei D. Robu

    40幅非常精美的字体艺术作品欣赏

    History Alphabet by Francisco Gigena

    40幅非常精美的字体艺术作品欣赏

    Some Fresh Stuff by Peter Tarka

    40幅非常精美的字体艺术作品欣赏

    Style Experiment by Dmitry Ske

    40幅非常精美的字体艺术作品欣赏

    Typographic Experiments by Kristian Kasi

    40幅非常精美的字体艺术作品欣赏

    Just Evolve X Nike SB Laced by Jonas Fleuraime

    40幅非常精美的字体艺术作品欣赏

    Posters by Evgeny Zhelvakov

    40幅非常精美的字体艺术作品欣赏

    Paper Typography by sabeena karnik

    40幅非常精美的字体艺术作品欣赏

    Soma Show by Andy Smith

    40幅非常精美的字体艺术作品欣赏

    You’re Not The Other by Bruno Santinho

    40幅非常精美的字体艺术作品欣赏

    Bright Type by Veaone

    40幅非常精美的字体艺术作品欣赏

    您可能还喜欢



    英文来源:A Showcase of Artistic Typography

    文章来源:梦想天空 ◆ 关注前端开发技术 ◆ 分享网页设计资源

    转载于:https://www.cnblogs.com/lhb25/archive/2011/10/09/showcase-of-artistic-typography-one.html

    展开全文
  • 梦想天空博客向大家分享过各种类型的优秀网站...今天这文章收集了世界32家精美的航空公司网站作品,一起欣赏。 01. Thai Airways 02. Turkish Airlines 03. Emirates 04. Lufthansa ...
  • 作为一个网页设计师,需要经常去关注优秀的网站作品,获取创作灵感,掌握最新的设计趋势。在这个竞争激烈的就业市场,个人作品集网站是最好的求职工具。因此,设计师们都竭尽所能设计一个有创造性的个人作品展示网站...
  • 单页网站是指只有一个...60佳灵感来自大自然的网页设计作品欣赏 分享100佳精美的作品集网站设计案例 编译来源: 梦想天空-专注Web开发技术和资源分享 国际来源: Single Page Websites: 50+ Awesome Example )
  • 插件,推荐优秀 网页设计 案例。 enila.fr Portfolio of Aline Caron. Les Illustrations de Lapin Made Like Me The home of illustrator Daryl Campbell. Marko Prljic Peter Pearson vectorstories I’m Helen ...
  • 在现在的Web设计中,绿色是设计师们最喜欢选用的颜色,绿色代表着活力、生长、宁静和青春。...60佳精美的绿色风格网页设计欣赏(上) 国际来源: TripwireMagazine 编译来源: 梦想天空-分享Web开发技术和设计资源
  • 对于网页设计师来说,制作一个作品集可能是一件非常有...60佳灵感来自大自然的网页设计作品欣赏   英文链接: 40 Inspiring Portfolio Designs 编译来源: 梦想天空 ◆ 关注前端开发技术 ◆ 分享网页设计资源
  • 在现在的Web设计中,绿色是设计师们最喜欢选用的颜色,...30个优秀的黑色风格网页设计作品欣赏 20佳精美的紫色风格网页设计作品欣赏 国际来源: TripwireMagazine 编译来源: 梦想天空-分享Web开发技术和设计资源
  • 单页网站是指只有一个页面...60佳灵感来自大自然的网页设计作品欣赏 分享100佳精美的作品集网站设计案例 编译来源: 梦想天空-分享Web开发技术和设计资源 国际来源: Single Page Websites: 50+ Awesome Example
  • 今天在我思考半天后决定有必要写上这文章成为我以后求学路上的初心,同时也非常乐意能给我的读者一些前进路上迷茫时候有些光照亮。 欣赏别人时候往往会忘记自己,比如在一朵光鲜亮丽的花朵面前可能会沉浸于其中你...
  • 25个优秀的国外单页网站设计作品欣赏   英文链接: Stunning Website Designs Inspired by Nature 编译来源: 梦想天空 ◆ 关注前端开发技术 ◆ 分享网页设计资源 转载于:...
  • 如果你正在为你的Flash网站设计项目寻找灵感和新思路,那么这文章推荐的15个非常有创意的Flash网页作品相信能帮助到你。Flash网站页面美观,互动性强,可以声形并茂,实现普通的HTML网站不能制造出的质感和动作,...
  • 最新的word排版实例20套(提高)适合各类人群。有助于提高你的word排版应用能力。
  • 原文地址为:12个优秀的 HTML5 网站设计案例欣赏 HTML5网站相关文章 15个精美的 HTML5 单页网站作品欣赏 10个很酷的 HTML5 字体应用演示网站 10个精美的 HTML5 企业网站欣赏 12个精美的 HTML5 个人网站欣赏 ...
  • 您可能还喜欢 12个优秀的 HTML5 网站设计案例欣赏 30个漂亮的个人作品集网页设计欣赏 分享35个非常漂亮的单页网站设计欣赏 ...今天这文章向大家分享30个优秀的旅行网站设计作品,一起欣赏这些精美的网...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,335
精华内容 1,734
关键字:

优秀美篇欣赏