Java学习笔记(3)

来源:互联网 发布:微信数据如何移到sd卡 编辑:程序博客网 时间:2024/05/17 22:57

设计原则

要评判某些设计比其他的设计优秀,就得定义一些在类的设计中重要的术语,以用来讨论设计的优劣。对于类的设计来说,有两个核心术语:耦合和聚合。 

耦合

耦合这个词指的是类和类之间的联系。之前的章节中提到过,程序设计的目标是一系列通过定义明确的接口通信来协同工作的类。耦合度反映了这些类联系的紧密度。我们努力要获得低的耦合度,或者叫作松耦合(loose coupling)。
耦合度决定修改应用程序的容易程度。在一个紧耦合的结构中,对一个类的修改也会导致对其他一些类的修改。这是要努力避免的,否则,一点小小的改变就可能使整个应用程序发生改变。另外,要想找到所有需要修改的地方,并一一加以修改,却是一件既困难又费时的事情。 另一方面,在一个松耦合的系统中,常常可以修改一个类,但同时不会修改其他类,而且整个程序还可以正常运作。

用封装降低耦合性。

聚合

聚合与程序中一个单独的单元所承担的任务的数量和种类相对应有关,它是针对类或方法这样大小的程序单元而言的。理想情况下,一个代码单元应该负责一个聚合的任务(也就是说,一个任务可以被看作是一个逻辑单元)。一个方法应该实现一个逻辑操作,而一个类应该代表一定类型的实体。聚合理论背后的要点是重用:如果一个方法或类是只负责一件定义明确的事情,那么就很有可能在另外不同的上下文环境中使用。遵循这个理论的一个额外的好处是,当程序某部分的代码需要改变时,在某个代码单元中很可能会找到所有需要改变的相关代码段。

如果我们要对String产生一些很复杂的操作(修改)的时候,一般用StringBuffer sb = new StringBuffer()比较好。这样子对系统的开销比较小。sb.append("ss");

用接口来实现聚合。

可扩展性

可扩展性的意思就是代码的某些部分不需要经过修改就能适应将来可能的变化。

容器

用容器来实现灵活性。HashMap.

框架加数据

从程序中识别出框架和数据,以代码实现框架,将部分功能以数据的方式加载,这样能在很大程度上实现可扩展性。

  • 命令的解析是否可以脱离if-else(看下面的图里的代码)
  • 定义一个Handler来处理命令
  • 用Hash表来保存命令和Handler之间的关系

把硬编码变成框架+数据。如对下面的代码进行修改


这里的逻辑是,接受到一个指令,去做一些事情(执行一个函数)。是一个一一对应的关系。可以想到HashMap可以实现一一对应的关系,但是函数本身不可以放到HashMap里面去。我们构造一个叫Handler的类,用它来帮我们实现一些动作。


抽象与接口

抽象

Shape类表达的是一种概念,一种共同属性的抽象集合,我们并不希望任何Shape类的对象会被创建出来。那么,我们就应该把这个Shape类定义为抽象的。我们用abstract关键字来定义抽象类。抽象类的作用仅仅是表达接口,而不是具体的实现细节。抽象类中可以存在抽象方法。抽象方法也是使用abstract关键字来修饰。抽象的方法是不完全的,它只是一个方法签名而完全没有方法体,不能有{}。public abstract void draw(Graphics g);

如果一个类有了一个抽象的方法,这个类就必须声明为抽象类。如果父类是抽象类,那么子类必须覆盖所有在父类中的抽象方法(实现抽象函数),否则子类也成为一个抽象类。一个抽象类可以没有任何抽象方法,所有的方法都有方法体,但是整个类是抽象的。设计这样的抽象类主要是为了防止制造它的对象出来。抽象类是不能产生对象的,但是可以定义变量——任何继承了抽象类的非抽象类的对象可以托付给这个变量。

数据与表现分离


Field管理data,不关心表现,View处理表现presentation,不关心data。cellMachine是第三方,它知道数据,也知道去变现。

程序的业务逻辑与表现无关

  • 表现可以是图形的也可以是文本的
  • 表现可以是当地的也可以是远程的


责任驱动的设计

将程序要实现的功能分配到合适的类/对象中去是设计中非常重要的一环。什么功能,由谁来做。


接口interface

  • 接口是纯抽象类
  • 所有的成员函数都是抽象函数
  • 所有的成员变量都是public static final
  • 接口规定了长什么样,但是不管里面有什么
  • interface是一种特殊的class,它和class的地位是一样的

(课程的例子)


我们把Cell设置为接口,让fox和rabbit去实现(implement)这个接口。同时,Fox必须override接口里面的函数。

public class Fox extends Animal implements Cell{//...}

任何实现了这个接口的类的对象都可以交给这个接口类型的变量。所以在这个例子中,Field处理的是Cell,而Fox实现了Cell这个接口,所以可以拿去给Feild来处理。Feild本身并不在意它拿到的具体的类型是什么(Field和View也只认识Cell,不认识Fox)。

实现接口

  • 类用extend,接口用implements
  • 类可以实现很多接口
  • 接口可以继承接口,但不能继承类
  • 接口不能实现接口

面向接口的编程方式

  • 设计程序时先定义接口,再实现类
  • 任何需要在函数间传入传出的一定是接口而不是具体的类
  • 是Java成功的关键之一,因为极其适合多人同时写一个大程序
  • 也是Java被批评的要点之一,因为代码量膨胀起来很快

控制反转和MVC设计模式

GUI

部件是创建GUI的独立部分,比如像按钮、菜单、菜单项、选择框、滑动条、文本框等。Java类库中有不少现成的部件。

布局是指如何在屏幕上放置组件。过去,大多数简单的GUI系统让程序员在二维坐标系上指定每个组件的x和y坐标(以像素点为单位),这对于现代的GUI系统来说太简单了。因为现代的GUI系统还得考虑不同的屏幕分辨率、不同的字体、用户可改变的窗口尺寸,以及许多其他使得布局困难的因素。所以需要有一种能更通用地指定布局的方法,比如,要求“这个部件应该在那个部件的下面“或者”这个部件在窗口改变尺寸时能自动拉伸,但是其他部件保持尺寸不变”。这些可以通过布局管理器(layout manager)来实现。

事件处理
是用来响应用户输入的技术。创建了部件并且放在屏幕上合适的位置以后,就得要有办法来处理诸如用户点击按钮这样的事情。Java类库处理这类事情的模型是基于事件的。 如果用户激活了一个部件(比如,点击按钮或者选择菜单项),系统就会产生一个事件。应用 程序可以收到关于这个事件的通知(以程序的一个方法被调用的方式),然后就可以采取程序该做的动作了。

布局管理器

Java里我们用的图形的这一套东西,叫swing。部件。容器。部件可以被放在容器里面。容器本身也是一种部件,可以被放在另一个容器里面。

对frame来说,默认的布局管理器是border。如果在程序里你不制定部件放在哪里(如何布局),那么就默认加到center里面去了,会存在替换掉其他部件的情况。


在layout manager的帮助下,程序员不需要自己去指定部件的布局的坐标(x=1,y=2这种),底层的东西自动地帮你去实现。


控制反转

Swing使用一个非常灵活的模型来处理GUI的输入:采用事件监听器的事件处理(event handling)模型。(消息机制)
Swing框架本身以及大部分部件在发生一些情况时会触发相关的事件,而其他的对象也许会对这些事件感兴趣。不同类型的动作会导致不同类型的事件。当点击一个按钮或选中一个菜单项,部件就会触发动作事件;而当点击或移动鼠标时,会触发鼠标事件;当框架被关闭或最小化时,会触发窗口事件。另外还有许多种其他事件。
所有的对象都可以成为任何这些事件的监听器,而一旦成为监听器,就可以得到这些事件触发的通知。
实现了众多监听器接口之一的对象就成为一个事件监听器。如果对象实现了恰当的接口,就可以注册到它想监听的组件上。

import javax.swing.JButton;//...JButton btn1 = new JButton("Click here");frame.add(btn1,BorderLayout.NORTH);btn1.addActionListener(new ActionListener(){ //在这个大括号里面制造了一个新的实现了ActionListener这个接口的类出来。匿名类。函数的内部类@overridepublic void actionPerformed(ActionEvent e){draw();}});

内部类

内部类就是指一个类定义在另一个类的内部,从而成为外部类的一个成员。因此一个类中可以有成员变量、方法,还可以有内部类。实际上Java的内部类可以被称为成员类,内部类实际上是它所在类的成员。所以内部类也就具有和成员变量、成员方法相同的性质。比如,成员方法可以访问私有变量,那么成员类也可以访问私有变量了。也就是说,成员类中的成员方法都可以访问成员类所在类的私有变量。内部类最重要的特点就是能够访问外部类的所有成员。

匿名类

  • 在new对象的时候给出的类的定义形成了匿名类
  • 匿名类可以继承某类,也可以实现某接口
  • Swing的消息机制广泛使用匿名类

内部类

  • 定义在别的类内部、函数内部的类
  • 内部类能直接访问外部的全部资源
  • 包括任何私有的成员
  • 外部是函数时,只能访问那个函数里final的变量

注入反转

  • 由按钮公布一个Listener接口和一对注册add/注销remove函数
  • 你的代码实现那个接口,将Listener对象注册在按钮上
  • 一旦按钮被按下,就会反过来调用你的Listener对象的某个函数

(用Listener这个接口实现我们自己的类(内部类,匿名类),用我们自己的类反过来调用Listener对象的某个函数)


MVC模式

JTable

用JTable类可以以表格的形式显示和编辑数据。JTable类的对象并不存储数据,它只是数据的表现。data。(数据和表现的分离)

我们做了一个JTable出来,只是说我们有这个表现,它的数据在哪呢?在其他的地方。


那个KCBData是另外一个implement了TableModel的类,用来存放表格里的数据。

MVC设计模式

  • 数据、表现和控制三者分离,各负其责
  • Model模型:保存和维护数据,提供接口让外部修改数据,通知表现需要刷新
  • View表现:从模型获得数据,根据数据画出表现
  • Control控制:从用户得到输入,根据输入调整数据

Control和View不直接产生联系(关系),就是说用户的操作不能直接修改View


异常处理与输入输出

异常

捕捉异常


把可能会产生异常的代码放在try里面。当捕捉到异常以后,那之后的代码不会执行,而是直接去执行catch里面的内容。

异常捕捉机制



捕捉到的异常

捕捉以后做什么?可以做一些输出。(但是,你肯定是回不去了)

void printStackTrace();


如果你捕捉到异常以后,不知道怎么处理,可以再度抛出,把这个exception抛给上一层来处理(上一层再一次的需要一个try/catch的机制来捕捉并处理)



异常机制

对于读文件这件事情,为了防止出错,用上异常机制


try的大括号里面的东西叫业务逻辑,business logic

异常机制最大的好处就是清晰地分开了正常的业务逻辑代码和遇到情况时的处理代码。


异常的抛出与声明

throw   告诉别人这里有一个异常。抛出。


异常声明(看下面的代码)



这样的代码的意义是:现在的readFile()的确只会抛出OpenException,但是以后有可能在更新后会抛出CloseException,而我们已经为此做好了准备


什么东西能throw?

——任何继承了Throwable类的对象。所有的异常继承自Exception,而Exception类继承自Throwable

throw new Exception();

异常捕捉时的匹配

父类的捕捉可以捕捉到所有抛出的子类类型的异常

所以catch (Exception e)可以捕捉到所有类型的异常

运行时刻异常异常

  • 像ArrayIndexOutOfBoundsException这样的异常是不需要声明的,这类异常叫“系统运行时的异常”
  • 但是如果没有适当的机制来捕捉,就会最终导致程序终止

异常遇到继承

异常声明

如果你调用一个声明会抛出异常的函数,那么你必须:

  • 把函数的调用放在try块中,并设置catch来捕捉所有可能抛出的异常;or
  • 声明自己会抛出无法处理的异常

异常声明遇到继承关系

  • 当覆盖override一个成员函数的时候,子类不能声明抛出比父类的版本更多的异常(但可以不抛出,或抛出父类声明抛出的异常的子类异常)
  • 在子类的构造函数中,必须声明父类可能抛出的全部异常
  • 但当覆盖构造函数的时候,子类可以声明抛出比父类的版本更多的异常
  • 覆盖父类的成员函数时不能增加声明抛出更多的异常的原因是,我们有可能拿着子类的对象当成父类的对象来看待,这时当我们拿着父类的变量去调用一个子类的函数的时候,我们得要处理好所有的异常
  • 但是在调用子类的构造函数的时候,会先调用父类的构造函数,所以父类的构造函数的抛出的所有异常在子类那里都得声明,而且可以增加新的抛出声明


流Stream

流是输入输出的方式

流是一维的、单向的


流的基础类(标准输入输出)

  • InputStream
  • OutputStream(这两个都只能做字节层面上的读和写)

文件流

  • FileInputStream
  • FileOutputStream
  • 对文件作读写操作
  • 实际工程中已经较少使用

流过滤器

  • DataInputStream
  • DataOutputStream
  • 用以读写二进制方式表达的基本数据类型



文本输入输出

文本流

  • 二进制数据采用InputStream/OutStream
  • 文本数据采用Reader/Writer



汉字编码

//...

0 0
原创粉丝点击