Interface duck类型与旧类型有何不同;变体';类型和/或接口?
我一直看到“ducktyping”这个短语到处流传,甚至遇到一两个代码示例。我懒得忙于自己的研究,有人能简单地告诉我:Interface duck类型与旧类型有何不同;变体';类型和/或接口?,interface,variant,duck-typing,Interface,Variant,Duck Typing,我一直看到“ducktyping”这个短语到处流传,甚至遇到一两个代码示例。我懒得忙于自己的研究,有人能简单地告诉我: “duck类型”和旧skool“variant类型”之间的区别,以及 提供一个示例,说明我可能更喜欢duck类型而不是variant类型,以及 提供一个我必须使用duck类型来完成的示例 我并不想因为怀疑这个“新”结构的力量而显得像禽鸟,我也不是因为拒绝做研究而回避这个问题,但我最近看到的关于它的蜂拥而至的炒作让我大吃一惊。在我看来,它似乎没有输入(也称为动态输入),所以
- “duck类型”和旧skool“variant类型”之间的区别,以及
- 提供一个示例,说明我可能更喜欢duck类型而不是variant类型,以及
- 提供一个我必须使用duck类型来完成的示例
…所以我还是不明白。它是一个神奇的省时工具,还是一个崭新的袋子里装着同样的旧东西?需要duck类型的示例在哪里?duck类型只是动态类型或后期绑定的另一个术语。duck类型是一种变体对象,它使用运行时可能定义或不定义的任何成员访问权限(例如obj.anywhere)进行解析/编译。我认为duck类型的核心是如何使用它。我们使用方法检测和实体的内省来知道如何处理它,而不是预先声明它将是什么(在那里您知道如何处理它) 它在OO语言中可能更实用,因为在OO语言中,原语不是原语,而是对象 我认为最好的总结方式是,在变体类型中,一个实体是/可以是任何东西,它是什么是不确定的,而不是一个实体只是看起来像任何东西,但你可以通过询问它来确定它是什么 有一件事我不相信不打字是可信的
sub dance {
my $creature = shift;
if( $creature->can("walk") ){
$creature->walk("left",1);
$creature->walk("right",1);
$creature->walk("forward",1);
$creature->walk("back",1);
}
if( $creature->can("fly") ){
$creature->fly("up");
$creature->fly("right",1);
$creature->fly("forward",1);
$creature->fly("left", 1 );
$creature->fly("back", 1 );
$creature->fly("down");
} else if ( $creature->can("walk") ) {
$creature->walk("left",1);
$creature->walk("right",1);
$creature->walk("forward",1);
$creature->walk("back",1);
} else if ( $creature->can("splash") ) {
$creature->splash( "up" ) for ( 0 .. 4 );
}
if( $creature->can("quack") ) {
$creature->quack();
}
}
my @x = ();
push @x, new Rhinoceros ;
push @x, new Flamingo;
push @x, new Hyena;
push @x, new Dolphin;
push @x, new Duck;
for my $creature (@x){
new Thread(sub{
dance( $creature );
});
}
任何其他方式都需要您对for函数设置类型限制,这将删除不同的种类,需要您为不同的种类创建不同的函数,这使得代码的维护非常困难
这真的很糟糕,仅仅是试图表现出良好的编舞 变量(至少我在VB6中使用过)包含一个单一的、定义良好的、通常是静态类型的变量。例如,它可能包含int、float或字符串,但变量int用作int,变量float用作float,变量字符串用作字符串
Duck类型改为使用动态类型。在duck类型下,如果变量恰好支持int、float或string在特定上下文中支持的特定方法,则变量可能可用作int、float或string
变体与duck类型的比较示例:
对于web应用程序,假设我希望我的用户信息来自LDAP而不是数据库,但我仍然希望我的用户信息可供基于数据库和ORM的web框架的其余部分使用
使用变体:没有运气。我可以创建一个变量,该变量可以包含UserFromDbRecord对象或UserFromLdap对象,但UserFromLdap对象将不可用于期望来自FromDbRecord层次结构的对象的例程
使用duck类型:我可以使用我的userfromdap类并添加几个方法,使其像UserFromDbRecord类一样工作。我不需要复制整个FromDbRecord接口,只需要复制我需要使用的例程即可。如果我做对了,这是一个非常强大和灵活的技术。如果我做错了,它会产生非常混乱和脆弱的代码(如果DB库或LDAP库发生更改,代码可能会被破坏)。请阅读Wikipedia关于duck键入的文章的第一段。
我可以有一个接口(iRunTable)来定义Run()方法。
如果我有另一个类具有这样的方法:
public void runsomerunable(IRunnable rn){…} 在duck类型友好的语言中,我可以将任何具有Run()方法的类传入RunSomeRunnable()方法。
在静态类型语言中,传递到RunSomeRunnable的类需要显式实现IRunnable接口
interface IDuck {
void Quack();
}
“如果它像鸭子一样跑”
变体至少更像.NET中的对象。@Kent Fredric
通过使用显式接口,您的示例完全可以不用duck类型来完成……是的,更丑陋,但这并非不可能
就我个人而言,我发现在接口中有定义良好的契约比依赖duck类型更好地强制执行高质量的代码……但这只是我的观点,对此持保留态度
public interface ICreature { }
public interface IFly { fly();}
public interface IWalk { walk(); }
public interface IQuack { quack(); }
// ETC
// Animal Class
public class Duck : ICreature, IWalk, IFly, IQuack
{
fly() {};
walk() {};
quack() {};
}
public class Rhino: ICreature, IWalk
{
walk();
}
// In the method
List<ICreature> creatures = new List<ICreature>();
creatures.Add(new Duck());
creatures.Add(new Rhino());
foreach (ICreature creature in creatures)
{
if (creature is IFly)
(creature as IFly).fly();
if (creature is IWalk)
(creature as IWalk).walk();
}
// Etc
公共接口ICreature{}
公共接口IFly{fly();}
公共接口IWalk{walk();}
公共接口i ack{quack();}
//等
//动物类
公共级鸭子:iFeature、IWalk、IFly、iPack
{
fly(){};
步行{};
庸医{};
}
公共级犀牛:ICreature,IWalk
{
步行();
}
//在方法中
列表生物=新列表();
添加(新鸭子());
添加(新犀牛());
foreach(生物中的特征生物)
{
如果(生物是IFly)
(作为IFly的生物)。飞行();
如果(生物是艾瓦克)
(作为我行走的生物)。行走();
}
//等
简单的答案是variant类型是弱类型的,而duck类型是强类型的
鸭型
class Daffy {
void Quack() {
Console.WriteLine("Thatsssss dispicable!!!!");
}
}
IDuck d = new Daffy();
d.Quack();
struct foo
{
int x;
iny y;
int z;
}
char * x = new char[100];
foo * pFoo = (foo *)x;
foo aRealFoo;
*pFoo = aRealFoo;
function Foo(x as object) as object
return x.Quack()
end function