目次
用Enum代替整数集
后记:
ホームページ データベース mysql チュートリアル 实战技巧:用Enum(枚举类型)取代整数集

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

Jun 07, 2016 pm 02:59 PM
android enum 交換する 実戦 スキル 列挙する タイプ

在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 までご連絡ください。

ホット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ヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

新しいレポートは、噂のSamsung Galaxy S25、Galaxy S25 Plus、Galaxy S25 Ultraのカメラアップグレードのひどい評価を提供します 新しいレポートは、噂のSamsung Galaxy S25、Galaxy S25 Plus、Galaxy S25 Ultraのカメラアップグレードのひどい評価を提供します Sep 12, 2024 pm 12:23 PM

ここ数日、Ice Universeは、サムスンの次期主力スマートフォンであると広く信じられているGalaxy S25 Ultraの詳細を着実に明らかにしている。とりわけ、リーカーはサムスンがカメラのアップグレードを1つだけ計画していると主張した

Samsung Galaxy S25 Ultraの最初のレンダリング画像がリークされ、噂のデザイン変更が明らかに Samsung Galaxy S25 Ultraの最初のレンダリング画像がリークされ、噂のデザイン変更が明らかに Sep 11, 2024 am 06:37 AM

OnLeaks は、X (旧 Twitter) のフォロワーから 4,000 ドル以上を集めようとして失敗した数日後、Android Headlines と提携して Galaxy S25 Ultra のファーストルックを提供しました。コンテキストとして、h の下に埋め込まれたレンダリング イメージ

IFA 2024 | TCLのNXTPAPER 14は、パフォーマンスではGalaxy Tab S10 Ultraに匹敵しませんが、サイズではほぼ匹敵します IFA 2024 | TCLのNXTPAPER 14は、パフォーマンスではGalaxy Tab S10 Ultraに匹敵しませんが、サイズではほぼ匹敵します Sep 07, 2024 am 06:35 AM

TCLは、2つの新しいスマートフォンの発表に加えて、NXTPAPER 14と呼ばれる新しいAndroidタブレットも発表しました。その巨大な画面サイズはセールスポイントの1つです。 NXTPAPER 14 は、TCL の代表的なブランドであるマット LCD パネルのバージョン 3.0 を搭載しています。

新しいレポートは、噂のSamsung Galaxy S25、Galaxy S25 Plus、Galaxy S25 Ultraのカメラアップグレードのひどい評価を提供します 新しいレポートは、噂のSamsung Galaxy S25、Galaxy S25 Plus、Galaxy S25 Ultraのカメラアップグレードのひどい評価を提供します Sep 12, 2024 pm 12:22 PM

ここ数日、Ice Universeは、サムスンの次期主力スマートフォンであると広く信じられているGalaxy S25 Ultraの詳細を着実に明らかにしている。とりわけ、リーカーはサムスンがカメラのアップグレードを1つだけ計画していると主張した

Vivo Y300 Pro は、7.69 mm のスリムなボディに 6,500 mAh のバッテリーを搭載 Vivo Y300 Pro は、7.69 mm のスリムなボディに 6,500 mAh のバッテリーを搭載 Sep 07, 2024 am 06:39 AM

Vivo Y300 Pro は完全に公開されたばかりで、大容量バッテリーを備えた最もスリムなミッドレンジ Android スマートフォンの 1 つです。正確に言うと、このスマートフォンの厚さはわずか 7.69 mm ですが、6,500 mAh のバッテリーを搭載しています。これは最近発売されたものと同じ容量です

Samsung Galaxy S24 FEは、4色と2つのメモリオプションで予想よりも低価格で発売されると請求されています Samsung Galaxy S24 FEは、4色と2つのメモリオプションで予想よりも低価格で発売されると請求されています Sep 12, 2024 pm 09:21 PM

サムスンは、ファンエディション(FE)スマートフォンシリーズをいつアップデートするかについて、まだ何のヒントも提供していない。現時点では、Galaxy S23 FE は 2023 年 10 月初めに発表された同社の最新版のままです。

Xiaomi Redmi Note 14 Pro Plusは、Light Hunter 800カメラを搭載した初のQualcomm Snapdragon 7s Gen 3スマートフォンとして登場します Xiaomi Redmi Note 14 Pro Plusは、Light Hunter 800カメラを搭載した初のQualcomm Snapdragon 7s Gen 3スマートフォンとして登場します Sep 27, 2024 am 06:23 AM

Redmi Note 14 Pro Plusは、昨年のRedmi Note 13 Pro Plus(Amazonで現在375ドル)の直接の後継者として正式に発表されました。予想通り、Redmi Note 14 Pro Plusは、Redmi Note 14およびRedmi Note 14 Proと並んでRedmi Note 14シリーズをリードします。李

Motorola Razr 50s は初期リークで新たな予算を折り畳める可能性があることを示す Motorola Razr 50s は初期リークで新たな予算を折り畳める可能性があることを示す Sep 07, 2024 am 09:35 AM

Motorola は今年数え切れないほどのデバイスをリリースしましたが、そのうち折りたたみ式デバイスは 2 つだけです。ちなみに、世界の大部分ではこのペアが Razr 50 および Razr 50 Ultra として受け入れられていますが、Motorola は北米では Razr 2024 および Razr 2 として提供しています。

See all articles