検索
ホームページデータベースmysql チュートリアル实战技巧:用Enum(枚举类型)取代整数集
实战技巧:用Enum(枚举类型)取代整数集Jun 07, 2016 pm 02:59 PM
androidenum交換する実戦スキル列挙するタイプ

在Android的API中可以发现有很多用整数集来作为参数的地方,先来看一下实例。 LinearLayout是大家所熟知的一个UI基本元素,它里面有一个方向的属性,可以通过以下方法来设置: LinearLayout.setOrientation(int); 使用的时候,通常都是这样: LinearLayout.s

在Android的API中可以发现有很多用整数集来作为参数的地方,先来看一下实例。
LinearLayout是大家所熟知的一个UI基本元素,它里面有一个方向的属性,可以通过以下方法来设置:

   LinearLayout.setOrientation(int);
使用的时候,通常都是这样:
LinearLayout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.setOrientation(LinearLayout.VERTICAL); 
但也可以这样使用:
LinearLayout.setOrientation(0); // LinearLayout.HORIZONTAL = 0
LinearLayout.setOrientation(1); // LinearLayout.VERTICAL = 0x01
甚至可以这样:
LinearLayout.setOrientation(Integer.MAX_VALUE);
LinearLayout.setOrientation(Integer.MIN_VALUE);
LinearLayout.setOrientation(2012);
因为方法setOrientation接收的参数是一个整数,所以你可以传任意合法的整数---至少这在编译时不会有任何问题。它只会在运行时可能引发问题,但如你所知,开发者只关注程序能否编译成功,至于运行时,那是用户关心的事儿,因为开发者不一定使用他们所开发出的程序。
除了这个例子,在Android的API中到处可以看到这种API,比如设置View的可见性,设置Wifi状态等等。都是定义了整数集,然后用整数来做为参数,并寄希望开发者能传递整数集中定义的常量来作为参数。但如你所知,并不是每个人都那么的守规矩,如果每个人都能遵守规则,这个世界就真的和谐了,蛋扯远了。
因为开发者通常只能关注编译,所以如果能把这个规则应用在编译时,那么就会大大减少出错的可能。有兴趣的朋友可以去试试看,给这些接收整数参数的方法传一些“平常”的数值,比如2012,Integer.MAX_VALUE,Integer.MIN_VALUE等等,看会出现什么状况。
另外,如果开发者传递与常量定义一致的整数值,虽然编译运行都不会有错,但代码的可读性会大大的降低,比如:

LinearLayout.setOrientation(0);
LinearLayout.setOrientation(1);
这完全没有错,但是代码的阅读者和维护者通常都会蛋疼的。
当然,Android自身还是有保护措施的,如果对API传递不合法参数,不会造成其他影响,只是设置不能生效,但API会使用默认值,因为对于每个内置参数,都有相应的默认值。如LinearLayout的orientation,默认值就是LinearLayout.HORIZONTAL,所以如果对setOrientation()传入非法值,LinearLayout会保持水平排列,无其他影响。后面有个对Linearlayout的orientation做的试验。
另外,如果在Layout XML文件中设置这些属性就不会有些问题,如:

<linearlayout android:orientation="vertical" android:gravity="center"></linearlayout>

因为XML布局会在编译时被处理,如果有非法的值,会有编译错误的。我想这也就是Android特别鼓励开发者用XML来制作所有的布局的一个原因吧。

实例,三个没有设置指向的线性布局,默认是水平放置,在代码中设置了几个离谱的值,发现它们还是水平的,也就是说设置离谱的值不会出错,但也不起作用:

运行结果如下:

实战技巧:用Enum(枚举类型)取代整数集

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center">
    <linearlayout android:id="@+id/linearlayout_test_1" android:layout_width="fill_parent" android:layout_height="wrap_content">
    
	  <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ff00ff00" android:background="#aa331155" android:layout_weight="1" android:textsize="18sp" android:text="Microsoft"></textview>
	  <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ffff0000" android:background="#aa117711" android:layout_weight="1" android:textsize="18sp" android:text="Apple"></textview>
	  <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ff0000ff" android:background="#aa774411" android:layout_weight="1" android:textsize="18sp" android:text="Google"></textview>
    </linearlayout>
    <linearlayout android:id="@+id/linearlayout_test_2" android:layout_width="fill_parent" android:layout_height="wrap_content">
    
      <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ff00ff00" android:background="#aa331155" android:layout_weight="1" android:textsize="18sp" android:text="Microsoft"></textview>
      <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ffff0000" android:background="#aa117711" android:layout_weight="1" android:textsize="18sp" android:text="Apple"></textview>
      <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ff0000ff" android:background="#aa774411" android:layout_weight="1" android:textsize="18sp" android:text="Google"></textview>
    </linearlayout>
    <linearlayout android:id="@+id/linearlayout_test_3" android:layout_width="fill_parent" android:layout_height="wrap_content">
    
      <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ff00ff00" android:background="#aa331155" android:layout_weight="1" android:textsize="18sp" android:text="Microsoft"></textview>
      <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ffff0000" android:background="#aa117711" android:layout_weight="1" android:textsize="18sp" android:text="Apple"></textview>
      <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:textcolor="#ff0000ff" android:background="#aa774411" android:layout_weight="1" android:textsize="18sp" android:text="Google"></textview>
    </linearlayout>
</linearlayout>
和:
package com.android.explorer;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;

public class LinearLayoutTest extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.linearlayout_test);
        LinearLayout one = (LinearLayout) findViewById(R.id.linearlayout_test_1);
        one.setOrientation(2012);
        LinearLayout two = (LinearLayout) findViewById(R.id.linearlayout_test_2);
        two.setOrientation(Integer.MAX_VALUE);
        LinearLayout three = (LinearLayout) findViewById(R.id.linearlayout_test_3);
        three.setOrientation(Integer.MIN_VALUE);
    }
}

用Enum代替整数集

其实很简单,用Enum(枚举)就可以很方便的解决这个问题,使用起来也不比定义整数集繁琐,同样的可读。另外的优点就是,它的封装更好,最重要的是它会在编译时被检查。因为Java是一种Strong Type,也就是说在编译时,编译器会对所有原型类型和参数类型进行检查,如果类型不对,并且没有强制转型的,就会报出编译错误,当然编译器所支持的自动转型除外。比如一个需要int,而传的参数是long,虽然都差不多,没有溢出等,但还是会有编译错误。
所以,如果LinearLayout使用Enum,就像这样定义:

public class LinearLayout extends ViewGroup {
    private Orientation mOrientation;
    
    public enum Orientation {
        HORIZONTAL, VERTICAL
    };
    
    public void setOrientation(Orientation dir) {
        mOrientation = dir;

    }

}
然后这样使用:
import android.widget.LinearLayout;

LinearLayout.setOrientation(Orientation.HORIZONTAL);
LinearLayout.setOrientation(Orientation.VERTICAL); 
那么,开发者就不会用错了,因为首先,它看到setOrientation所需要的参数是一个Orientation的枚举类型,就会自然的传送Orientation中定义的类型;另外,如果传其他的值,比如0或者1,编译器也不会答应的。
可悲的是Android中几乎所有的API都是以整数集的方式来定义的,所以就要时刻提醒自己和组里的人,一定要传所定义的整数集中的常量。
那么我们能做的,除了要传整数集中定义的常量,对于那些以整数集方式定义的API,以外。更重要的是当自己定义接口的时候,尽量用Enum而不要使用整数集。
还有一点需要注意的是,对于某些弱类型语言,也就是说在编译时不会对类型做特别细致的检查,比如C++,C等,那么即使使用了Enum,也不一定安全,因为对于C++和C来讲Enum中的常量与整数常量完全一样,连编译器都分不清。所以,对于这类语言,只能寄希望于开发者了。

后记:

写完这篇,让我想起了另外一些与参数定义相关的问题,比如布尔型参数也不是一个很好的设计,因为使用者很难到底应该传True还是传False,特别是当方法名字不能体现Boolean参数作用时和文档不够清楚的时候。如果只有一个参数还好,根据方法名字和常识都能知道,比如:
Button.setEnabled(true); // enable the button
Button.setEnabled(false); // disable the button
但对于某些情况,当方法的名字不能体现Boolean参数的作用时,或是多于一个参数时,而方法的主要目的又不能体现Boolean参数的作用时,就很不清楚,比如:
// com/android/mms/data/ContactList.java
public String[] getNumbers(boolean);
您能猜出来这个boolean变量是决定是否要为彩信对联系人做特殊的处理吗?您在使用这个API的时候能很快知道该传True还是该传False吗?当读到这些语句的时候:
String[] mms = getNumbers(true);
String[] sms = getNumbers(false);
您能知道True和False的含义与作用吗?至少我看到这样的代码时,如果不去跟踪它的实现,是猜不出来的。
但现实的问题是,API通常又需要从调用者那里得到做还是不做的决定。一个可行的途径是用方法来封装和隐藏,比如:

Button.setEnabled(true); // enable the button
Button.setEnabled(false); // disable the button
可以改成:
Button.enable();
Button.disable();
这是简单的情况,对于稍复杂的情况,比如后一个例子,可以添加另外的接口,而不是用重载方法,但内部的实现,可能还是需要重载,但是这就把问题缩小了,起码对使用者来说是隐藏的:
// com/android/mms/data/ContactList.java
public String[] getNumbersForSms();
public String[] getNumbersForMms();
这样一来,对外来讲就是良好的封装。内部实现可能还是需要一个类似这样的私有方法:
// com/android/mms/data/ContactList.java
public String[] getNumbersForSms() {
   return getNumbers(false);
}
public String[] getNumbersForMms() {
   return getNumbers(true);
}
private String[] getNumbers(boolean) {
   // implementation
}
但至少把问题缩小化了,也可以加上注释来说明。就不必导致使用者来猜方法的用法和含义了。
对于使用Boolean作为参数的弊端,可以参考陈皓的这篇博客,讲的很透彻。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
手把手教你uniapp和小程序分包(图文)手把手教你uniapp和小程序分包(图文)Jul 22, 2022 pm 04:55 PM

本篇文章给大家带来了关于uniapp跨域的相关知识,其中介绍了uniapp和小程序分包的相关问题,每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分,希望对大家有帮助。

Golang实战:数据导出功能的实现技巧分享Golang实战:数据导出功能的实现技巧分享Feb 29, 2024 am 09:00 AM

数据导出功能在实际开发中是非常常见的需求,特别是在后台管理系统或者数据报表导出等场景中。本文将以Golang语言为例,分享数据导出功能的实现技巧,并给出具体的代码示例。1.环境准备在开始之前,确保已经安装好Golang环境,并且熟悉Golang的基本语法和操作。另外,为了实现数据导出功能,可能还需要使用第三方库,比如github.com/360EntSec

MySQL表设计实战:创建一个电商订单表和商品评论表MySQL表设计实战:创建一个电商订单表和商品评论表Jul 03, 2023 am 08:07 AM

MySQL表设计实战:创建一个电商订单表和商品评论表在电商平台的数据库中,订单表和商品评论表是两个非常重要的表格。本文将介绍如何使用MySQL来设计和创建这两个表格,并给出代码示例。一、订单表的设计与创建订单表用于存储用户的购买信息,包括订单号、用户ID、商品ID、购买数量、订单状态等字段。首先,我们需要创建一个名为"order"的表格,使用CREATET

Java开发实战:集成七牛云云存储服务实现文件上传Java开发实战:集成七牛云云存储服务实现文件上传Jul 06, 2023 pm 06:22 PM

Java开发实战:集成七牛云云存储服务实现文件上传引言随着云计算和云存储的发展,越来越多的应用程序需要将文件上传至云端进行存储和管理。云存储服务的优势在于高可靠性、可扩展性和灵活性。本文将介绍如何使用Java语言开发,集成七牛云云存储服务,实现文件上传功能。七牛云简介七牛云是国内领先的云存储服务提供商,其提供了全面的云存储和内容分发服务。用户可以通过七牛云提

深入学习 Elasticsearch 查询语法与实战深入学习 Elasticsearch 查询语法与实战Oct 03, 2023 am 08:42 AM

深入学习Elasticsearch查询语法与实战引言:Elasticsearch是一款基于Lucene的开源搜索引擎,主要用于分布式搜索与分析,广泛应用于大规模数据的全文搜索、日志分析、推荐系统等场景。在使用Elasticsearch进行数据查询时,灵活运用查询语法是提高查询效率的关键。本文将深入探讨Elasticsearch查询语法,并结合实际案例给出

Vue实战:日期选择器组件开发Vue实战:日期选择器组件开发Nov 24, 2023 am 09:03 AM

Vue实战:日期选择器组件开发引言:日期选择器是在日常开发中经常用到的一个组件,它可以方便地选择日期,并提供各种配置选项。本文将介绍如何使用Vue框架来开发一个简单的日期选择器组件,并提供具体的代码示例。一、需求分析在开始开发之前,我们需要进行需求分析,明确组件的功能和特性。根据常见的日期选择器组件功能,我们需要实现以下几个功能点:基础功能:能够选择日期,并

MySQL表设计实战:创建一个电影信息表和演员表MySQL表设计实战:创建一个电影信息表和演员表Jul 01, 2023 pm 08:16 PM

MySQL表设计实战:创建一个电影信息表和演员表导语:在数据库设计中,表的创建是一个非常关键的环节。本文将以电影信息表和演员表为例,详细介绍如何进行MySQL表的设计和创建,并附上相应的代码示例。一、电影信息表设计和创建电影信息表是用来存储电影的相关信息,包括电影名称、导演、上映时间、电影类型等字段。下面是电影信息表的设计和创建过程,首先我们需要选择合适的字

Django框架中的后台管理系统实战Django框架中的后台管理系统实战Jun 18, 2023 am 11:31 AM

Django是一款流行的Web应用程序开发框架,它有着丰富的组件和工具,能够简化和加速Web应用程序的开发过程。其中,Django中的后台管理系统是一个重要的组件,它提供了一个功能强大的管理界面,使得我们可以方便地管理我们的应用程序的数据,包括创建、修改、删除、查询等操作,同时也提供了许多扩展的功能。在本文中,我们将介绍如何在Django中创建一个简单的后台

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。