JAVA面向对象编程学习(6)抽象与接口

抽象

在第一周就有一个Shape类的例子。这个类有很多的子类,每个子类也都实现了父类的方法。实际上父类Shape只是一个抽象的概念而并没有实际的意义。如果请你画一个圆,你知道该怎么画;如果请你画一个矩形,你也知道该怎么画。但是如果我说:“请画一个形状,句号”。你该怎么画?同样,我们可以定义Circle类和Rectangle类的draw(),但是Shape类的draw()呢?

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

如果一个类有了一个抽象的方法,这个类就必须声明为抽象类。如果父类是抽象类,那么子类必须覆盖所有在父类中的抽象方法,否则子类也成为一个抽象类。一个抽象类可以没有任何抽象方法,所有的方法都有方法体,但是整个类是抽象的。设计这样的抽象类主要是为了防止制造它的对象出来。

读起来非常地抽象。。

首先我们研究下Shape Class里面的代码

package shapes;

import java.awt.Graphics;

public abstract class Shape {
	
	public abstract void draw(Graphics g);
	
}

项目内的架构
项目架构
在这里,我们虽然没有看到具体的代码,但是我们能看得出来Shape为下层构造方法提供了一种概念,它不是实现,而是一种概念性质的抽象,不管你实际上是什么类型的东西,你的方法都应该含有draw(),这就是概念,实际上这种概念在实际上是不存在的,它是我们用来为某一类物质定性,那么也就是说,这种东西是不能被制造出来的(不能被实例化为对象)。

只要有一个函数是抽象的,那么这个类就是抽象的。

值得注意的是:抽象函数/抽象类可以用来定义变量,任何继承了抽象类的非抽象类的对象可以赋给这个变量。
那么这个继承了抽象类的非抽象类的对象所定义的类,必须对父类中所定义的抽象函数进行实现。

两种抽象

-与具体相对
表示一种概念而非实体
-与细节相对
表示在一定程度上忽略细节而着眼大局

数据表现与分离

关系图
设计理念:数据表现与分离,就是管数据的对象和管表现的对象互不关联,由第三方进行链接。
将程序要实现的功能分配到合适的类/对象中去设计是非常重要的一环

问题1:为什么没有Cell.setAlive()?

Cell本身只是存储数据,setAlive这些动作是要由业务方面的类来执行

问题2:关于Field.getNeighbour()

为什么Field.getNeighbour()不直接看Cell.isAlive()来返回一个数字,而是要返回一个数组让外面来数数?
我们是希望在getNeighbour()函数里面得到是当前处理的cell的邻居死活的状态信息,这是一手数据,是原材料,我们是不希望这东西经过加工,即使当前我们确实是想计算出死亡数量,但是这个业务逻辑是应该放在cellMachine里面的,这样在日后我们想修改规则的时候直接在最接近业务逻辑的那个cellMachine类里面直接修改,而不是去一层层地向下深入寻找,这尤其在大型的继承链很深的程序里是很不便的一件事情,就好比cell不需要知道Field里面会怎么处理它,Field也不必知道cellMachine会怎么处理它的信息一样,都只是向更高层提供信息,这样有效降低耦合度,增强可扩展性,便于程序的维护

问题3:Cell为什么不自己判断邻居情况?

为什么不是由Cell自己判断自己的邻居的情况来决定自己是否应该被die或reborn?
cell无法自己判断邻居的状态,考虑到耦合

应该让cell专注在alive的资料存储上

接口(interface)

概念

表达的是一种概念和规范
接口是纯抽象类
-所有的成员函数都是抽象函数
-所有的成员变量都是public static final
接口定义了长什么样,但是不管里面有什么

就是说在视频所说的情况下,我们不能够把两个不同的类(语义没办法相同的类)把他引入到filed中去,我们就可以采取这样的办法,用implement的方法来实现这个类,实现了这个类之后,filed就会认可他是个cell,从而达到可以被用而不引起语义混淆的情况。

	public class Fox extends Aminal implements Cell
	{
		//TO DO SOMETHING
	}
	public Cell place(int row, int col, Cell o) {
		Cell ret = field[row][col];
		field[row][col] = o;
		return ret;
	}
public interface Cell//地位相当于class interface是一种特殊的class
{

}

这一段代码的含义是接受一个实现了Cell功能的变量,无论他是不是属于是Cell抽象类的实现类对象,只要实现了这个接口,就可以被接入

实现接口

类用extends,接口用implement
类可以实现很多接口
接口可以继承接口,但不能继承类
接口不能实现接口

接口设计模式 面向接口的编程方式

先定义接口再实现类
任何需要在函数间传入传出的一定是接口而不是具体的类

问题1:Fox.breed()和Rabbit.breed()几乎一样

Fox.breed()和Rabbit.breed()几乎一样,有什么好办法修改?注意Fox和Rabbit的breed()返回的具体类型不同。
在父类animals里面加一个fox和rabbit共有的breed函数

问题2:Cell要不要知道Field?

在城堡游戏中,Handler是知道Game的;在细胞自动机中,Cell是不知道Field的。在现在版本的狐狸与兔子中,Cell也是不知道Field的。
那么,如果让Cell知道Field会怎样呢?两种做法各有什么优缺点呢?

Cell是一个接口, 其成员变量必须是static final的, 因此对于这个游戏而言要让其认识Field, 如果还有一个其他的Field就无法实现了, 我认为是得不偿失的. 如果作为代替用Animal去认识Field的话, 意义会更明确, 实现起来也相对容易, 但是这就意味着Animal要产生一个对Field直接的依赖, 如果后面需要换一种显示方式, 这边也要进行相应的改动.

问题3:要不要Animal的列表?

如果另外用一个ArrayList来表示所有的动物,每一步遍历这个列表而非整个Field,这样做是否更好?
提示:这样就需要每个Animal知道自己在Field里的位置

我认为这样可以,首先增加了提供动物位置信息的函数,其次遍历的时间复杂度由O(n2)变成了O(n);

问题4:要不要把数据和表现进一步分离?

现在Cell接口其实是承担了两个责任的。在Field看过来,它只认识Cell,它认为Cell是存放在其中的数据。而对于View来说,它看到的是Cell所具有的draw方法,从这个角度来说Cell表示了表现。
有没有必要两种分开。比如有一个Cell抽象类表示可以放进Field的东西,另一个Drawable接口表示可以被Vier画出来的东西?

当实现的功能更多时,比如可以选择多种显示方法,可以选择不同形状或者生存条件的Field,而导致Cell接口必须要填充更多东西的时候,

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值