论坛首页 Java版

接口是一种正交分解技术

浏览 11106 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
时间:2005-03-03
age0 写道
两种设计方法都面临一个相同的问题:既然是person或者human,不论是manager或者是employee都会有相同的eat和sleep的实现,但是上面两种设计都强制设计者必须为manager和employee编写各自的eat和sleep的实现,这与 concept :implment 达到 1 :1 的追求是背道而驰的。

第一种只是要求Manager必须实现eat和sleep方法,对于具体实现来说,concept :impelment 可能是1 :1也可能是1:n。
比如这样的Manager实现:
[code:1]class Manager implements IHuman, IManager{
private IHuman _human;
private IManager _manager;
public Manager (IHuman human,IManager manager)
{...}
public void eat()
{
_human.eat();
}
public void sleep()
{
_human.sleep();
}

}[/code:1]
   
0 请登录后投票
时间:2005-03-03
至于抽象类+subclass,一般情况我都会用final class 聚合interface来代替,除非该抽象类是不可正交分解的,这样粒度较细,更容易复用。
   
0 请登录后投票
时间:2005-03-03
dengyin2000 写道
abstract class Person{

String name;
int age;

public void eat(){};
public void sleep(){};

}
eat sleep 可不是抽象方法..


dengyin2000说的不就又回到楼主说的"is a"的关系
java不允许类的多重继承是产生深层树状结构的重要原因
但是使用接口又产生了实现不一致的问题

因为java的接口实际上是一个"黑盒"设计,它只对外暴露它的名称
称为:介面继承
这样使得实现接口变得危险,因为接口的方法实际上是多态形式
我们不知道多态方法到底是怎样实现的
对于不同的对象,实现方法可能不同

在这里要澄清楼主所带来的误道
楼主所说的是有一定道理的,但是楼主举的例子不恰当,造成了混淆

楼主的这种设计方法:
引用
interface IHuman {
bool eat();
bool sleep();
};
interface IManager{
bool fireEmployee();
};
class Manager implements IHuman, IManager{…};


实际上隐晦的违反了OCP原则,因为在楼主的设计中,IHuman这个接口已经不单单是个属性,而且是个实体,而IManager则可以完全作为一个属性,这种做法使得Human的行为有机会被其他的使用者更改,如:
Class Employee implements IHuman{…};
就可能造成Human实体的实现方法不同
所以实际上该例子是因违反了Liskov替换原则进而违反了OCP原则

所以,使用接口时(即面向对象中的多重继承概念)
要牢记使用的多重继承的约束条件:(同时注意楼主违反的第5、6条
假设有一个木造门﹐则:
1. 此木造门是门的一种(a kind of)。
2. 但门不是木造门的一部份(a part of)。
3. 木造门是木制品的一种。
4. 但木制品不是木造门的一部份。
5. 木制品不是门的一种。
6. 门也不是木制品的一种。


所以,在使用接口时,应注意在什么情况下使用,因为接口同C++的虚函数不同,虽然同是多重继承,但是C++的虚函数有纯虚和非纯虚的区别,这使得在功能上,实际上C++是比java的interface要多一些。
【摘录】
但这并不代表Java的interface就比较差﹐因为interface的观念较简单﹐全部动态的抽象方法也正代表着Java为一纯面向对象的语言。与C++不同的是﹐C++考虑许多执行效率的问题﹐所以语言本身就变的较复杂化﹐同时C++的编译器也是公认难写的﹐多重继承更是一大挑战。
Java的interface虽然好象少了一些功能﹐但其实那些功能在一般的程式设计中也很少碰到﹔并且观念简洁的Java interface﹐在程序设计时更可以避免许多陷阱。总之﹐两种程式语言机制是很难比较谁好谁坏的
   
0 请登录后投票
时间:2005-03-03
flyingbug 写道

所以实际上该例子是因违反了Liskov替换原则进而违反了OCP原则

应该这么说:
所以实际上该例子是因遵从了Liskov替换原则进而遵从了OCP原则
   
0 请登录后投票
时间:2005-03-03
pufan 写道
flyingbug 写道

所以实际上该例子是因违反了Liskov替换原则进而违反了OCP原则

应该这么说:
所以实际上该例子是因遵从了Liskov替换原则进而遵从了OCP原则


哦?能否详细说说?
   
0 请登录后投票
时间:2005-03-03
Alan.Weng 写道
age0 写道
chengren 写道
兄弟,经理吃饭的方法和俺们的民工的吃饭方法可未必一样啊。


说得没错,吃饭方法未必一样,但也未必不一样,现实中是两种情况都有,但上面两种设计却假设经理和民工的吃饭方法必定是不一样的,即使完全相同你也要去写两遍相同的代码。

如果说继承是一个极端,那么接口就是另外一个极端,接口本来是要解决继承产生的问题,却引出了继承已经解决的问题。



如此说来,用抽象类不是更好?如果吃饭方法一样,那就继承;否则,Override

你可能走进了误区,假如民工是男人,而经理是女人呢?如果是接口,那么我可以实现工人和女人这两个接口.
   
0 请登录后投票
时间:2005-03-03
flyingbug 写道

实际上隐晦的违反了OCP原则,因为在楼主的设计中,Human这个类已经不单单是个属性,而且是个实体,而Manager则可以完全作为一个属性,这种做法使得Human的行为有机会被其他的使用者更改,如:
Class Employee implements IHuman{…};
就可能造成Human实体的实现方法不同


那照你的说法,应该是 Class Human implements IManager{…}才对?
   
0 请登录后投票
时间:2005-03-03
interface IHuman {
bool eat();
bool sleep();
};

interface IManager{
bool fireEmployee();
};

Class Manager implements IHuman, IManager
{
private IHuman __human;
public Manager ( IHuman ,human )
{
__human=human;
}
public void eat()
{
__human.eat();
}
public fireManager()
{
..........
}
}

Interface/Aggreegation 完全可以替代继承。如果说继承是父子关系,那么Interface/Aggreegation就是一种嵌套关系,比如一个MM穿一件内衣总不雅观,那么给他套上一个衬衫,天气冷了衬衫太单薄就套件羊毛衫。MM,内衣,羊毛衫,衬衫,都是正交分解,互不相干,要出门了一件件穿上去,要上床了可以脱的一丝不挂,多好。你总没有见过那个裁缝把,内衣,衬衫,羊毛衫作到一起的吧。
如果语言支持mixin(像Python),或者template(类似C++),那么就可以避免一些method distribution的代码。Java么,只要类设计的合理,这些代码也无所谓的了。
   
0 请登录后投票
时间:2005-03-03
你们都错喽,经理不过是一个角色,谁说机器人就不能做经理啊,机器人可不一定要吃饭

偶不是想bt, 我完全同意楼主的看法
   
0 请登录后投票
时间:2005-03-03
Trustno1 写道

Interface/Aggreegation 完全可以替代继承。如果说继承是父子关系,那么Interface/Aggreegation就是一种嵌套关系,比如一个MM穿一件内衣总不雅观,那么给他套上一个衬衫,天气冷了衬衫太单薄就套件羊毛衫。MM,内衣,羊毛衫,衬衫,都是正交分解,互不相干,要出门了一件件穿上去,要上床了可以脱的一丝不挂,多好。你总没有见过那个裁缝把,内衣,衬衫,羊毛衫作到一起的吧。
如果语言支持mixin(像Python),或者template(类似C++),那么就可以避免一些method distribution的代码。Java么,只要类设计的合理,这些代码也无所谓的了。


不要光说不练,把你的设计show出来,MM要穿衣服容易实现,MM脱衣服是不是这样设计 Class MM not implements IColth ?

inherit/Aggreegation 才是完美的组合,Interface就素那浮云。
   
0 请登录后投票
论坛首页 Java版

跳转论坛:
JavaEye推荐