Archive for the ‘oop’ Category

尽量使用接口而不是抽象类

Friday, August 24th, 2007

就像许多前辈都指出的“尽量使用接口而不是抽象类”,我从中有所感悟,用我前面举的抽象类的例子来解释一下如何用接口替换抽象类(专门写这篇,是想看看我是不是真正理解了-只有能表达出来的东西才算你真正理解,背诵不算:),呵呵)

不提倡使用抽象类的原因是因为你一旦继承了这个类就是这个类型了(被定义了一种语义),就像前面我举的关于内核的例子,你继承了AbstractBrowserCore,那么它就代表了一种浏览器的内核。因为不管java还是as它们都是单继承的,也就是只有一个父类,父类的定义显然是很宝贵的,不能随随便便的来定义。
我在前面的例子上再举个例子:
像FF和IE都提供了很多不错的插件(ActiveX),这么好的资源不能浪费啊!!!我决定不只是利用其它浏览器的内核,它们的插件我也要!还有其它功能(如书签什么的),我准备把它作成服务。
这些服务包括:
使用其它浏览器的内核,使用浏览器插件,得到浏览器书签等等。

上面每个功能我都用接口来定义:

[code:php]

interface IBrowse

{

function browse(url:String):String;

function back():void;

function forward():void;

function home():void;

}

interface IPlugin

{

function getPlugins():Array;

function invoke(plugin:Object):Boolean;

}

interface IBookmark

{

function addBookmark(b:Object):void;
function getBookmarks():Array;

}

我用一个FFBrowserService来实现前面定义的所有接口(只用FF来举例):

public class FFBrowserService implements IBrowse, IPlugin, IBookmark

{

public ovarride function browse(url:String):String

{

// 调用FF的api

}

.........

// 实现的所有接口方法

..........

}

使用 FFBrowserService类:

public class BrowserApp

{

private var _browserService:Object;

private var _bookmark:Array;

public function set browserService(bs:Object):void

{this._browserService = bs;}

public function init()

{

if(this._browser is IBookmark)

{

var bm:IBookmark = this._browserService as IBookmark;

this._bookmark = bm.getBookmarks();

}

}

public function onBackBtRelease():void

{

if(this._browserService is IBrowse == false) return;

var b:IBrowse = this._browserService as IBrowse;

b.back();

}

public function onEnterRelease():void

{

if(this._browserService is IBrowse == false) return;

var b:IBroser = this._browserService as IBrowse;

checkStatus(b.browse(inputText.text)); //检查http状态

}

public function pluginOnRelease(pl:Object):void

{

if(this._browserService is IPlugin == false) return;

var p:IPlugin = this._browserService as IPlugin;

p.invoke(pl);

}

}

[/code]

像这样用接口而不是用抽象类是不是觉得更加的灵活呢?假设一种浏览器不支持插件,那么可以不用实现IPlugin这个接口。而从语义上来讲,FFBrowserService这个类代表了整个第三方浏览器所提供的服务,而不仅仅是内核而已。

希望我的理解对你有所帮助:)

抽象类简单介绍

Friday, August 24th, 2007

抽象类就是不能实例化的类,因为它内部的一些抽象方法还没有被实现(你不可能去创建一个连方法内容都没有的类的对象)。
它的作用是,把一些子类共有的方法全部集中在父类(也就是这个抽象类)中,但它还提供一些抽象方法(所谓抽象方法就是没有实现的方法只是声明了一下方法名和参数)子类一定要去实现它们。
问题就在,为什么它要提供这些抽象方法?为什么它自己不实现这些方法?
我简单举个例子,比如说:
我觉得现在的一些浏览器的功能不能满足我,我想做个浏览器自己实现了一些功能,但是浏览器的内核我没有能力来写(能写出来我就是高手啦,哈哈),所以我想调用其它现有浏览器的内核(就像the world做的那样),但是我想做的比它还好,因为the world只能用IE内核,我想IE和firefox的内核都能用(可能还有其它的内核),觉得IE好的用IE内核,觉得FF好的用FF的内核,根据用户的爱好设定。
其它功能部分我都实现了,为了满足我前面的需求我建了一个抽象类:
[code:php]
import flash.errors.IllegalOperationError;
public class AbstractBrowserCore
{
……..
public function someOtherCommonFunction(){….} //一些非抽象公共函数
………
// 抽象方法
public function browse(url:String):String
{throw new IllegalOperationError(”abstract function must be overriden”);}
}

// IE实现类
public class IEBrowserCore extends AbstractBrowserCore
{
override public function browse(url:String):String
{
// 调用IE的api
}
}

// FF实现类
public class FFBrowserCore extends AbstractBrowserCore
{
override public function browse(url:String):String
{
// 调用FF的api
}
}

// 未来浏览器内核的实现类
public class SomeOtherBrowserCore extends AbstractBrowserCore
{
override public function browse(url:String):String
{
// 调用其它浏览器内核的api
}
}

// 调用这些类
public class RunApp
{
private var bcore:AbstractBrowserCore;
public function set broswerCore(core:AbstractBrowserCore):void
{
this.bcore = core;
}

public function onKeyDownEvent(e:Event)
{
var code:String = this.bcore.browse(this.inputText.text);
if(code == 404) outputText.text(”文件未找到”);
else if…..
}
}
[/code]
用户只要设置了他喜欢的内核就可以了,这就是多态的力量!可以随意更换实现,但是主程序更本就不需要有什么改变,就像FF的插件一样,非常灵活,来去自由,容易扩展。
其实像http就是一个非常抽象的协议,我们根本就不关心服务器的后台到底是什么,管它是jsp,php,asp,我们只要能看到我们想看到的就可以了。
不知道有没有解释清楚,呵呵:-)

AS3对Abstract Class的实现

Wednesday, August 22nd, 2007

http://www.zeuslabs.us/2007/08/19/enforcing-abstract-classes-at-runtime-in-actionscript-3/

看了下他关于用AS3实现的Abstract Class,个人感觉这个实现有点麻烦而且有效率的损失。我试着自己写了一个Abstract Class实现:

抽象类:

[code:php]

package jeff.abstract
{
import flash.errors.IllegalOperationError;

public class MyAbstractClass
{

public function MyAbstractClass(self:MyAbstractClass)
{
if(self != this)
{
throw new IllegalOperationError("Abstract class did not receive reference to self. MyAbstractClass cannot be instantiated directly.");
}
}

public function mustBeOverriden1(param:String):void
{
throw new IllegalOperationError("abstract function must be overriden");
}

public function mustBeOverriden2(param:String):void
{
throw new IllegalOperationError("abstract function must be overriden");
}

}
}

实现类:

package jeff.abstract
{
public class MyImplementClass extends MyAbstractClass
{
public function MyImplementClass()
{
super(this);
}

public override function mustBeOverriden1(param:String):void
{
trace("From or1 "+param);
}

public override function mustBeOverriden2(param:String):void
{
trace("From or2 " + param);
}
}
}

未实现抽象类中的方法的实现类:

package jeff.abstract
{
public class NotImplementAbstract extends MyAbstractClass
{
public function NotImplementAbstract()
{
super(this);
}
}
}

运行类:

package {
import flash.display.Sprite;
import jeff.abstract.MyAbstractClass;
import jeff.abstract.MyImplementClass;
import jeff.abstract.NoImplementAbstract;

public class AbstractTest extends Sprite
{
public function AbstractTest()
{
var a:MyAbstractClass = new MyImplementClass();
a.mustBeOverriden1("hi");
a.mustBeOverriden2("world");

// output: From or1 hi

From or2 world

var b:MyAbstractClass = new NotImplementAbstract();
b.mustBeOverriden1("hi");
b.mustBeOverriden2("world");

// throw exceptions

}
}
}

[/code]
我只是在抽象类中要被抽象的方法中写了个异常抛出语句,意思就是如果你没有覆盖它的话,那么在运行的时候调用这个方法就会抛出异常(并不是像他那样在new的时候就检查是否覆盖了抽象方法)。如果对我这个实现有其它看法的话欢迎评论:)