목차
用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 Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

새로운 보고서는 소문난 삼성 갤럭시 S25, 갤럭시 S25 플러스, 갤럭시 S25 울트라 카메라 업그레이드에 대한 비판적인 평가를 제공합니다. 새로운 보고서는 소문난 삼성 갤럭시 S25, 갤럭시 S25 플러스, 갤럭시 S25 울트라 카메라 업그레이드에 대한 비판적인 평가를 제공합니다. Sep 12, 2024 pm 12:23 PM

최근 아이스 유니버스는 삼성의 차기 플래그십 스마트폰으로 널리 알려진 갤럭시 S25 울트라에 대한 세부 정보를 꾸준히 공개해 왔습니다. 무엇보다도 유출자는 삼성이 카메라 업그레이드를 하나만 가져올 계획이라고 주장했습니다.

삼성 갤럭시 S25 울트라, 디자인 변경 루머가 공개된 첫 번째 렌더링 이미지 유출 삼성 갤럭시 S25 울트라, 디자인 변경 루머가 공개된 첫 번째 렌더링 이미지 유출 Sep 11, 2024 am 06:37 AM

OnLeaks는 이제 Android Headlines와 제휴하여 X(이전 Twitter) 팔로어로부터 4,000달러 이상의 수익을 창출하려는 시도가 실패한 지 며칠 후 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은 두 가지 새로운 스마트폰을 발표하는 것과 함께 NXTPAPER 14라는 새로운 Android 태블릿도 발표했는데, TCL의 거대한 화면 크기는 판매 포인트 중 하나입니다. NXTPAPER 14는 TCL의 시그니처 브랜드인 무광택 LCD 패널 버전 3.0을 갖추고 있습니다.

새로운 보고서는 소문난 삼성 갤럭시 S25, 갤럭시 S25 플러스, 갤럭시 S25 울트라 카메라 업그레이드에 대한 비판적인 평가를 제공합니다. 새로운 보고서는 소문난 삼성 갤럭시 S25, 갤럭시 S25 플러스, 갤럭시 S25 울트라 카메라 업그레이드에 대한 비판적인 평가를 제공합니다. Sep 12, 2024 pm 12:22 PM

최근 아이스 유니버스는 삼성의 차기 플래그십 스마트폰으로 널리 알려진 갤럭시 S25 울트라에 대한 세부 정보를 꾸준히 공개해 왔습니다. 무엇보다도 유출자는 삼성이 카메라 업그레이드를 하나만 가져올 계획이라고 주장했습니다.

Vivo Y300 Pro는 7.69mm의 슬림한 본체에 6,500mAh 배터리를 탑재했습니다. Vivo Y300 Pro는 7.69mm의 슬림한 본체에 6,500mAh 배터리를 탑재했습니다. Sep 07, 2024 am 06:39 AM

Vivo Y300 Pro는 방금 완전히 공개되었으며 대용량 배터리를 갖춘 가장 얇은 중급 Android 휴대폰 중 하나입니다. 정확히 말하면 스마트폰의 두께는 7.69mm에 불과하지만 배터리 용량은 6,500mAh입니다. 최근 출시된 것과 동일한 용량이다.

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

모토로라는 올해 셀 수 없이 많은 기기를 출시했지만 그 중 폴더블 기기는 2개뿐이었습니다. 맥락에 따라 전 세계 대부분이 Razr 50 및 Razr 50 Ultra로 쌍을 받았지만 Motorola는 북미에서 Razr 2024 및 Razr 2로 제공합니다.

See all articles