当前位置:  编程技术>移动开发
本页文章导读:
    ▪资料资源管理        文件资源管理 原文:http://blog.donews.com/zchening/archive/2011/03/09/490.aspx 原文2:http://book.chinaunix.net/showart.php?id=8116   这是一个有图标的文件资源管理器,也许在网上的基于Android的market上有很多.........
    ▪ abstract与interface的差异        abstract与interface的区别 abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract class和interface之间在对.........
    ▪ NSMutableArray 与NSArray的差别       NSMutableArray 与NSArray的区别 那位高手帮帮忙,给说一下NSMutableArray 和NSArray的,在用法上有什么不同?NSMutableArray能添加、插入、删除对象,而NSArray不能NSMutableArray 实现的是 NSMutableCopy protocol, N.........

[1]资料资源管理
    来源: 互联网  发布时间: 2014-02-18
文件资源管理

原文:http://blog.donews.com/zchening/archive/2011/03/09/490.aspx

原文2:http://book.chinaunix.net/showart.php?id=8116

 

这是一个有图标的文件资源管理器,也许在网上的基于Android的market上有很多比较精美的文件资源管理器,这里我拿这个出来讲并不在于我做的界面如何的精美,而相反我这里的重点并不在界面,我只是想通过这么个列子和大家一起分享Android开发中的一下知识点:(1)目录的遍历(2)自定义Adapter(3)如何取得文件类型,以及调用系统打开对应的文件。这三点也是本程序的关键点所在,如果将这三个知识点掌握了,我想理解这个应用程序也就不再话下。

那么现在让我们一起来阅读代码吧,首先我们知道Android API提供的ArrayAdapter对象只允许存入String数组或List对象,所以在显示文件列表时,只能以一段字符串来显示文件的名称,如果要同时显示文件夹和文件的图标,以及文件名称,甚至文件类型、大小等信息,则必须要自定义一个实现Adapter Interface的对象,就可以自定义想要呈现的Layout,达到同时显示图片文件ICON与多个文字信息的效果,Android API中提供了BaseAdapter(Android.widget.BaseAdapter)对象,只要继承此对象就可以实现出属于自己的Adapter。

实现此范例时,须要先准备文件图标的ICON图片文件,并保存在/res/drawable/文件夹下,图片文件路径如下:

1 /res/drawable/back01.png; 回到根目录的图标
2 /res/drawable/back02.png; 回到上一层的图标
3 /res/drawable/doc.png;     文件的图标
4 /res/drawable/folder.png;   文件夹的图标
运行效果图:

源码:

/* import程序略 */

 

public class EX05_15 extends ListActivity

{

  /* 对象声明

     items:存放显示的名称

     paths:存放文件路径

     rootPath:起始目录

  */

  private List<String> items=null;

  private List<String> paths=null;

  private String rootPath="/";

  private TextView mPath;

  private View myView;

  private EditText myEditText;

 

  @Override

  protected void onCreate(Bundle icicle)

  {

    super.onCreate(icicle);

    /* 加载main.xml Layout */

 

    setContentView(R.layout.main);

    /* 初始化mPath,用以显示目前路径 */

    mPath=(TextView)findViewById(R.id.mPath);

    getFileDir(rootPath);

  }

 

  /* 取得文件架构的方法 */

  private void getFileDir(String filePath)

  {

    /* 设置目前所在路径 */

    mPath.setText(filePath);

    items=new ArrayList<String>();

    paths=new ArrayList<String>();

   

    File f=new File(filePath); 

    File[] files=f.listFiles();

 

    if(!filePath.equals(rootPath))

    {

      /* 第一笔设置为[回到根目录] */

      items.add("b1");

      paths.add(rootPath);

      /* 第二笔设置为[回上层] */

      items.add("b2");

      paths.add(f.getParent());

    }

    /* 将所有文件添加到ArrayList中 */

    for(int i=0;i<files.length;i++)

    {

      File file=files[i];

      items.add(file.getName());

      paths.add(file.getPath());

    }

 

    /* 使用自定义的MyAdapter来将数据传入ListActivity */

    setListAdapter(new MyAdapter(this,items,paths));

  }

 

  /* 设置ListItem被按下时要做的动作 */

  @Override

  protected void onListItemClick(ListView l,View v,int position,

                                 long id)

  {

    File file = new File(paths.get(position));

    if(file.canRead())

    {

      if(file.isDirectory())

      {

        /* 如果是数据夹就再执行getFileDir() */

        getFileDir(paths.get(position));

      }

      else

      {

        /* 如果是文件调用fileHandle() */

        fileHandle(file);

      }

    }

    else

    {

      /* 跳出AlertDialog显示权限不足 */

      new AlertDialog.Builder(this)

          .setTitle("Message")

          .setMessage("权限不足!")

          .setPositiveButton("OK",

            new DialogInterface.OnClickListener()

            {

              public void onClick(DialogInterface dialog,int which)

              {

              }

            }).show();

    }

  }

 

  /* 处理文件的方法 */

  private void fileHandle(final File file){

    /* 按下文件时的OnClickListener */

    OnClickListener listener1=new DialogInterface.OnClickListener()

    {

      public void onClick(DialogInterface dialog,int which)

      {

        if(which==0)

        {

          /* 选择的item为打开文件 */

          openFile(file);

        }

        else if(which==1)

        {

          /* 选择的item为更改文件名 */

          LayoutInflater factory=LayoutInflater.from(EX05_15.this);

          /* 初始化myChoiceView,使用rename_alert_dialog为layout */

          myView=factory.inflate(R.layout.rename_alert_dialog,null);

          myEditText=(EditText)myView.findViewById(R.id.mEdit);

          /* 将原始文件名先放入EditText中 */

          myEditText.setText(file.getName());

 

          /* new一个更改文件名的Dialog的确定按钮的listener */

          OnClickListener listener2=

          new DialogInterface.OnClickListener()

          {

            public void onClick(DialogInterface dialog, int which)

            {

              /* 取得修改后的文件路径 */

              String modName=myEditText.getText().toString();

              final String pFile=file.getParentFile().getPath()+"/";

              final String newPath=pFile+modName;

 

              /* 判断文件名是否已存在 */

              if(new File(newPath).exists())

              {

                /* 排除修改文件名时没修改直接送出的情况 */

                if(!modName.equals(file.getName()))

                {

                  /* 跳出Alert警告文件名重复,并确认是否修改 */

                  new AlertDialog.Builder(EX05_15.this)

                      .setTitle("注意!")

                      .setMessage("文件名已经存在,是否要覆盖?")

                      .setPositiveButton("确定",

                       new DialogInterface.OnClickListener()

                      {

                        public void onClick(DialogInterface dialog,

                                            int which)

                        {

                          /* 文件名重复仍然修改会覆盖掉已存在的文件 */

                          file.renameTo(new File(newPath));

                          /* 重新生成文件列表的ListView */

                          getFileDir(pFile);

                        }

                      })

                      .setNegativeButton("取消",

                       new DialogInterface.OnClickListener()

                      {

                        public void onClick(DialogInterface dialog,

                                            int which)

                        {

                        }

                      }).show();

                }

              }

              else

              {

                /* 文件名不存在,直接做修改动作 */

                file.renameTo(new File(newPath));

                /* 重新生成文件列表的ListView */

                getFileDir(pFile);

              }

            }

          };

 

          /* create更改文件名时跳出的Dialog */

          AlertDialog renameDialog=

            new AlertDialog.Builder(EX05_15.this).create();

          renameDialog.setView(myView);

 

          /* 设置更改文件名按下确认后的Listener */

          renameDialog.setButton("确定",listener2);

          renameDialog.setButton2("取消",

          new DialogInterface.OnClickListener()

          {

            public void onClick(DialogInterface dialog, int which)

            {

            }

          });

          renameDialog.show();

        }

        else

        {

          /* 选择的item为删除文件 */

          new AlertDialog.Builder(EX05_15.this).setTitle("注意!")

              .setMessage("确定要删除文件吗?")

              .setPositiveButton("确定",

               new DialogInterface.OnClickListener()

              {

                public void onClick(DialogInterface dialog,

                                        int which)

                {         

                  /* 删除文件 */

                  file.delete();

                  getFileDir(file.getParent());

                }

              })

              .setNegativeButton("取消",

               new DialogInterface.OnClickListener()

              {

                public void onClick(DialogInterface dialog,

                                        int which)

                {

                }

              }).show();

        }

      }

    };

 

    /* 选择一个文件时,跳出要如何处理文件的ListDialog */

    String[] menu={"打开文件","更改文件名","删除文件"};

    new AlertDialog.Builder(EX05_15.this)

        .setTitle("你要做什么?")

        .setItems(menu,listener1)

        .setPositiveButton("取消",

         new DialogInterface.OnClickListener()

        {

          public void onClick(DialogInterface dialog, int which)

          {

          }

        })

        .show();

  }

 

  /* 在手机上打开文件的方法 */

  private void openFile(File f)

  {

    Intent intent = new Intent();

    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    intent.setAction(android.content.Intent.ACTION_VIEW);

 

    /* 调用getMIMEType()来取得MimeType */

    String type = getMIMEType(f);

    /* 设置intent的file与MimeType */

    intent.setDataAndType(Uri.fromFile(f),type);

    startActivity(intent);

  }

 

  /* 判断文件MimeType的方法 */

  private String getMIMEType(File f)

  {

    String type="";

    String fName=f.getName();

    /* 取得扩展名 */

    String end=fName.substring(fName.lastIndexOf(".")+1,

                                    fName.length()).toLowerCase();

 

    /* 根据扩展名的类型决定MimeType */

    if(end.equals("m4a")||end.equals("mp3")||end.equals("mid")

       ||end.equals("xmf")||end.equals("ogg")||end.equals("wav"))

    {

      type = "audio";

    }

    else if(end.equals("3gp")||end.equals("mp4"))

    {

      type = "video";

    }

    else if(end.equals("jpg")||end.equals("gif")||end.equals("png")

             ||end.equals("jpeg")||end.equals("bmp"))

    {

      type = "image";

    }

    else

    {

      /* 如果无法直接打开,就跳出软件列表供用户选择 */

      type="*";

    }

    type += "/*";

    return type;

  }

}

 

src/irdc.ex05_15/MyAdapter.java

自定义的Adapter对象,并以file_row.xml作为Layout,程序中依照文件的类型来决定要显示的图标是什么。

 

/* import程序略 */

 

/* 自定义的Adapter,继承android.widget.BaseAdapter */

public class MyAdapter extends BaseAdapter

{

  /* 变量声明

     mIcon1:回到根目录的图片文件

     mIcon2:回到上一层的图片

     mIcon3:文件夹的图片文件

     mIcon4:文件的图片

  */

  private LayoutInflater mInflater;

  private Bitmap mIcon1;

  private Bitmap mIcon2;

  private Bitmap mIcon3;

  private Bitmap mIcon4;

  private List<String> items;

  private List<String> paths;

  /* MyAdapter的构造器,传入三个参数  */ 

  public MyAdapter(Context context,List<String> it,List<String> pa)

  {

    /* 参数初始化 */

    mInflater = LayoutInflater.from(context);

    items = it;

    paths = pa;

    mIcon1 = BitmapFactory.decodeResource(context.getResources(),

                                                  R.drawable.back01);

    mIcon2 = BitmapFactory.decodeResource(context.getResources(),

                                                  R.drawable.back02);

    mIcon3 = BitmapFactory.decodeResource(context.getResources(),

                                                  R.drawable.folder);

    mIcon4 = BitmapFactory.decodeResource(context.getResources(),

                                                  R.drawable.doc);

  }

 

  /* 因继承BaseAdapter,需重写以下方法 */

  @Override

  public int getCount()

  {

    return items.size();

  }

 

  @Override

  public Object getItem(int position)

  {

    return items.get(position);

  }

 

  @Override

  public long getItemId(int position)

  {

    return position;

  }

 

  @Override

  public View getView(int position,View convertView,ViewGroup par)

  {

    ViewHolder holder;

   

    if(convertView == null)

    {

      /* 使用自定义的file_row作为Layout */

      convertView = mInflater.inflate(R.layout.file_row, null);

      /* 初始化holder的text与icon */

      holder = new ViewHolder();

      holder.text = (TextView) convertView.findViewById(R.id.text);

      holder.icon = (ImageView) convertView.findViewById(R.id.icon);

     

      convertView.setTag(holder);

    }

    else

    {

      holder = (ViewHolder) convertView.getTag();

    }

 

    File f=new File(paths.get(position).toString());

    /* 设置[回到根目录]的文字与icon */

    if(items.get(position).toString().equals("b1"))

    {

      holder.text.setText("Back to /");

      holder.icon.setImageBitmap(mIcon1);

    }

    /* 设置[回到上一层]的文字与icon */

    else if(items.get(position).toString().equals("b2"))

    {

      holder.text.setText("Back to ..");

      holder.icon.setImageBitmap(mIcon2);

    }

    /* 设置[文件或文件夹]的文字与icon */

    else

    {

      holder.text.setText(f.getName());

      if(f.isDirectory())

      {

        holder.icon.setImageBitmap(mIcon3);

      }

      else

      {

        holder.icon.setImageBitmap(mIcon4);

      }

    }

    return convertView;

  }

 

  /* class ViewHolder */

  private class ViewHolder

  {

    TextView text;

    ImageView icon;

  }

}

自定义的Adapter对象,并以file_row.xml作为Layout,程序中依照文件的类型来决定要显示的图标是什么。 file_row.xml
<!--?xml version="1.0" encoding="utf-8"?-->
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent">
  <imageview android:id="@+id/icon" android:layout_width="30dip" android:layout_height="30dip">
  </imageview>
  <textview android:id="@+id/text" android:layout_gravity="center_vertical" android:layout_width="0dip" android:layout_weight="1.0" android:layout_height="wrap_content" android:textcolor="@drawable/black">
  </textview>
</linearlayout>

写在最后:本范例重点在于如何通过实现自定义的Adapter对象来自定义想要呈现的Layout,以及如何在手机上实现打开文件的功能。

通过自定义的Adapter,可以在ListView中放入任何想要呈现的widget对象,如RadioButton、CheckBox、EditText等,如此一来,在开发程序时,就可以做更多样化得应用。

在主程序中自定义了openFile()这个方法来做打开文件的动作,程序内容如下

  /* 调用getMIMEType()来取得MimeType */
   String type = getMIMEType(f);
   /* 设置intent的file和MimeType */
   intent.setDataAndType(Uri.fromFile(f),type);
startActivity(intent);

其中使用intent.setDataAndType(Uri,type)来指定要打开的文件及文件的MIME Type,并以startActivity()的方式来打开文件。getMIMEType()这个方法中,依据文件的拓展名来设置文件的MIME Type,MIME Type格式为“文件类型/文件拓展名”,目前程序中针对部分类型的文件做MIME Type的判断,其余的文件则一律将MIME Type设置为“*/*”,当系统受到文件的类型为“*”时,会自动弹出应用程序的菜单,让用户自己选择要用哪个程序打开文件。

 

 

 

 

扩展学习

程序中使用java.io.File的renameTo(File newFile)来更改文件名称,需要注意的是,当修改后的文件名原本就已经存在时,程序会将原来的文件覆盖掉,且不会有任何的提示,这样等于是无意间删除了原来旧有的文件。为了预防这种状况发生,程序中先以file.exists()来判断是否有已经存在的文件,如果有,会先跳出警示的AlertDialog,请用户确认是否要覆盖旧文件。假如更改文件名,则可以预防文件无意间被删除的情况发生。

如果想让文件资源管理器的管理功能更强大,可以运用File对象提供的其他方法来实现,比如说,可用file.mkdir()来实现添加文件夹的功能;canRead()、canWrite()可以让文件资源管理器具备权限控制的功能。

程序中使用了许多的AlertDialog,Android API提供了android.app.AlertDialog.Builder对象,可以快速产生AlertDialog对象,以下介绍几种常用的方法,如表5-5所示。

表5-5                                                    Mechod名称及功能

 

Method名称

相关
  • 1 Eclipse资源管理(4)
  • 2 Eclipse资源管理(3)
  • 3 Eclipse资源管理(2)
  • 4 Eclipse资源管理(1)
  • 5 资源管理中的方式
移动开发-热门移动开发-最新移动开发-其它
  • 1 十分难缠的signal 11 (SIGSEGV)
  • 2 Can't create handler inside thread that has not called Looper.prepare() 错误有关问题
  • 3 Dex Loader Unable to execute Multiple dex files define解决办法
  • 4 解决 Google Play下载施用 "Google Play Store 已停止运行&quot
  • 5 WAP网页获得用户的手机号码
  • 6 如何判断Activity是否在运行
  • 7 SlidingMenu+ViewPager兑现侧滑菜单效果
  • 8 makeKeyAndVisible的功用
  • 9 关于Unable to execute dex: Java heap space 解决方法
  • 10 RelativeLayout设置居中对齐有关问题
  • 1 播发声音文件AVAudioPlayer
  • 2 改变银屏显示方式已经加载图片
  • 3 2013-十-31 TCP/IP 协议簇
  • 4 Java I/零 总体框架图
  • 5 拿碗的铠甲勇者
  • 6 女友可能出轨 想知道在QQ和别人的聊天记录
  • 7 objective C中的字符串(3)
  • 8 java.lang.ClassNotFoundException: Didn't find class "Activity" on path: /da
  • 9 LG Optimus G Pro 相干
  • 10 怎么创建对话框
  • 1 power键跟音量键组合实现截图功能
  • 2 深入viewgroup.onintercepttouchevent1点
  • 3 实现默认文字统制的textview
  • 4 BroadcastReceiver要领
  • 5 Andriod耗时操作的处置(音乐播放器欢迎界面)
  • 6 MGTemplateEngine模版发动机
  • 7 用 lipo 下令裁剪出需要的 architecture
  • 8 疑惑为什么报错了
  • 9 Tiledmap编辑操作技巧
  • 10 视图切换的形式
  • 上一篇: 软件工程师的无线互联创业陷阱
  • 下一篇: abstract与interface的差异
各类>>热门搜索
WEB开发
  • Web开发
  • Web前端
  • HTML/CSS
  • PHP
  • ASP
  • JavaScript
  • vbScript
  • Ajax
  • 网页设计
  • 跨浏览器开发
  • 高性能WEB开发
  • Web Service
  • XML/SOAP
  • CGI
数据库
  • 数据库
  • SQL
  • MySQL
  • Oracle技术
  • Oracle管理
  • Oracle开发
  • Oracle面试
  • Oracle Exception
  • Sql Server
  • Informix
  • Sybase
  • DB2
  • Access
  • VFP
  • 数据仓库
  • 高性能数据库开发
  • 其他数据库
移动开发
  • 移动开发
  • Android
  • Iphone
  • Windows Mobile
  • Symbian
  • BlackBerry
  • QT开发
  • Brew
  • MeeGo
  • 移动平台
  • 移动软件开发
  • 电信IT应用开发
  • 移动应用
企业软件/开发
  • 企业开发
  • 企业信息化
  • 行业应用
  • GIS
  • SAP
  • Tivoli
  • Lotus
  • Exchange
  • SharePoint
  • 报表
硬件/嵌入开发
  • 嵌入开发
  • WinCE
  • 硬件开发
  • 单片机
  • 汇编语言
  • 驱动开发
  • Wireless
  • VxWorks
JAVA
  • Java Web开发
  • J2EE
  • J2SE
  • J2ME
  • Java面试
  • Java相关
  • Eclipse
  • Java Exception
应用服务器
  • 应用服务器
  • Apache
  • IIS
  • JBoss
  • WebSphere
  • Weblogic
  • ColdFusion
软件工程/管理/测试
  • 研发管理
  • 项目管理
  • 开发过程
  • 开发方法
  • 软件设计
  • 设计模式
  • 软件架构设计
  • 敏捷开发
  • 微创软件开发
  • CVS/SVN
  • VSTS
  • PowerDesigner
  • Rational
  • 软件测试
.NET
  • C#
  • ASP.NET
  • .NET Framework
  • VB Dotnet
  • VC
  • .NET分析设计
  • .NET组件控件
  • J#
  • Delphi
  • .NET报表
  • LINQ
  • .NET新技术
  • .NET面试
  • .NET相关
  • DotNet Exception
Linux/Unix
  • Linux/Unix
  • Solaris
  • AIX
多媒体
  • 多媒体/流媒体开发
  • 多媒体设计
  • 交互式开发
  • Flash
  • 图形/图像
  • 图像工具使用
  • Flex
  • AutoCAD
  • Silverlight
开发语言/框架
  • C++
  • C语言
  • C++ Builder
  • VB
  • PB
  • Ruby/Rails
  • perl/python
  • 编程
  • 其他开发语言
专题开发/技术/项目
  • 网络通信
  • Open API
  • 信息/网络安全
  • IBM云计算
  • Paypal
  • VOIP
  • Google技术
  • 人工智能
  • 搜索引擎
  • CUDA
综合
  • 综合
  • 互联网
  • 操作系统
  • 开源软件
  • 共享软件
  • 系统运维
高性能开发
  • 高性能WEB开发
  • 高性能数据库开发
  • 高性能计算
  • 多核软件开发
  • 数据结构与算法
  • 游戏开发
  • 云计算
硬件设备
  • 网络设计维护
  • 数码设备
  • 电脑整机及配件
  • 装机与升级
  • 外设及办公设备
  • 电脑硬件
  • 交换机/路由器
Windows
  • Windows
  • Windows2000
  • Windows xp
  • Windows7
  • Office
  • VBA
  • VC/MFC
  • Delphi
培训认证
  • 软件培训
  • IT认证
  • Oracle认证考试
  • 软件水平考试
  • IT课程
  • 计算机图书
  • 计算机英语
软件开发程序错误异常Exception Copyright © 2009-2013 MyException 版权所有


    
[2] abstract与interface的差异
    来源: 互联网  发布时间: 2014-02-18
abstract与interface的区别
abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析,试图给开发者提供一个在二者之间进行选择的依据。 

理解抽象类 

abstract class和interface在Java语言中都是用来进行抽象类(本文中的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语言中用于定义抽象类的一种方法,请读者注意区分)定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢? 

在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。 

在面向对象领域,抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者一定知道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。 


从语法定义层面看abstract class和interface 

在语法层面,Java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。 

使用abstract class的方式定义Demo抽象类的方式如下: 

abstract class Demo { 
abstract void method1(); 
abstract void method2(); 
… 
} 

使用interface的方式定义Demo抽象类的方式如下: 

interface Demo { 
void method1(); 
void method2(); 
… 


在abstract class方式中,Demo可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstract class。 

      从编程的角度来看,abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。 

首先,abstract class在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。 

其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会 增加一些复杂性,有时会造成很大的麻烦。 

在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面(一般通过abstract class或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那么可能就只需要修改定义在abstract class中的默认行为就可以了。 

同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了"one rule,one place"原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。 


从设计理念层面看abstract class和interface 

上面主要从语法定义和编程的角度论述了abstract class和interface的区别,这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面:abstract class和interface所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。 

前面已经提到过,abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的(参考文献〔3〕中有关于"is a"关系的大篇幅深入的论述,有兴趣的读者可以参考)。对于interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。 

考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示: 

使用abstract class方式定义Door: 

abstract class Door { 
abstract void open(); 
abstract void close(); 


  
使用interface方式定义Door: 


interface Door { 
void open(); 
void close(); 


  
其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。 

如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢(在本例中,主要是为了展示abstract class和interface反映在设计理念上的区别,其他方面无关的问题都做了简化或者忽略)?下面将罗列出可能的,并从设计理念层面对这些不同的方案进行分析。 

一: 

简单的在Door的定义中增加一个alarm方法,如下: 

abstract class Door { 
abstract void open(); 
abstract void close(); 
abstract void alarm(); 


  
或者 

interface Door { 
void open(); 
void close(); 
void alarm(); 


  
那么具有报警功能的AlarmDoor的定义方式如下: 

class AlarmDoor extends Door { 
void open() { … } 
void close() { … } 
void alarm() { … } 


  
或者 

class AlarmDoor implements Door { 
void open() { … } 
void close() { … } 
void alarm() { … } 
} 

这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之依然。 

二: 

既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用abstract class方式定义;两个概念都使用interface方式定义;一个概念使用abstract class方式定义,另一个概念使用interface方式定义。 

显然,由于Java语言不支持多重继承,所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。 

如果两个概念都使用interface方式来定义,那么就反映出两个问题:1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用interface方式定义)反映不出上述含义。 

如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在Java语言中表示一种继承关系,而继承关系在本质上是"is a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示: 

abstract class Door { 
abstract void open(); 
abstract void close(); 

interface Alarm { 
void alarm(); 

class AlarmDoor extends Door implements Alarm { 
void open() { … } 
void close() { … } 
    void alarm() { … } 


  
这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系,interface表示的是"like a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。

    
[3] NSMutableArray 与NSArray的差别
    来源: 互联网  发布时间: 2014-02-18
NSMutableArray 与NSArray的区别


那位高手帮帮忙,给说一下NSMutableArray 和NSArray的,在用法上有什么不同?

NSMutableArray能添加、插入、删除对象,而NSArray不能
NSMutableArray 实现的是 NSMutableCopy protocol, NSArray 实现的是NSCopy protocol

    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
NOSQL iis7站长之家
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3