DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: l_hx
今日帖子: 4
在线用户: 4
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 inbreak (入侵) ★☆☆☆☆ -
盒子活跃会员
2023/3/11 23:25:08
标题:
经常使用类,对 interface 了解不多,最近看资料后,我对它的应用场景有些搞不懂。 浏览:707
加入我的收藏
楼主: 除了规范一些函数/过程。自管理生命周期外,
好象作用并不大呀。

但是缺点也很明显了。
1、性能低下;
2、调整麻烦,就是按住 Ctrl + 函数/过程名,直接跳到 接口的定义。具体的实现还得再慢慢找。

-------

或许是我的理解太初级了。
哪位大神举一些应用场景,让我更明白点。谢谢。
----------------------------------------------
我是菜鸟,己经搞了十多年了,但是我仍然很菜。
作者:
男 doersoft (yixsys.com) ★☆☆☆☆ -
普通会员
2023/3/11 23:53:44
1楼:   当类之间不能用【同父类】达到抽像实现相同的方法属性时,接口就作为补充出现.
  接口就像合同,不同的类和实例,只要声明实现相同的某个接口,就可以用AS操作符去执行合同中的方法,就是可以按合同办事.
  类是强继承,接口更宽松灵活些,相应也要付出些代价。
----------------------------------------------
delphi|vue|golang yixsys|yixerp|mes|srm
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/12 1:40:54
2楼: unit uMyClasses_Interfaces;

interface

type
  IMyInterf_BASE_ONE = interface
    ['{29461F68-E415-4B05-813D-7EA88FED8889}']  // <-- CTRL+SHIFT+G
    //
    // procedures or functions
    procedure prcHelloWorld_ONE;
    function fncHelloWorld_ONE: integer;
    //
    // property usage:
    function GetHelloWorld_ONE: string;
    procedure SetHelloWorld_ONE(Value: string);
    property propHelloWorld_ONE: string read GetHelloWorld_ONE write SetHelloWorld_ONE;
  end;

  IMyInterf_BASE_TWO = interface
    ['{A43D4865-9D94-4746-9EA4-DE689C44F6DD}']  // <-- CTRL+SHIFT+G
    procedure prcHelloWorld_TWO;
  end;

  // in your classes, you decive where define it.... in according with your necessity!!!
  // private
  // protected
  // public
  // published
  //
  // xxxxx = class( 1 class, 1 interface, 2 interface, 3 interface, etc... etc... etc...  )
  //
  // TIntefacedObject is a default when using this definition, but exists many other options...
  //
  TMyClass_ONE_UsingInterface = class(TInterfacedObject, IMyInterf_BASE_ONE)
    //
  protected // all sub-classes (inheriting...) can use it
    FMyValue: string;
    //
    // example using: Private and Public sections!!! you decide in your class definition!!!
    //
  private
    // property
    function GetHelloWorld_ONE: string;
    procedure SetHelloWorld_ONE(Value: string);

  public
    // procedures or functions
    procedure prcHelloWorld_ONE;
    function fncHelloWorld_ONE: integer;
    //
    // property
    property propHelloWorld_ONE: string read GetHelloWorld_ONE write SetHelloWorld_ONE;
  end;

  // here, Class_TWO is inheriing all defitions from Class_ONE, including the interface defintions (Interf_ONE) + Interf_TWO

  TMyClass_TWO_Using_Inheriting_Other_Interface = class(TMyClass_ONE_UsingInterface, IMyInterf_BASE_TWO)
  public
    // from "IMyInterf_BASE_TWO"
    procedure prcHelloWorld_TWO;
  end;

implementation

{ TMyClass_ONE_UsingInterface }

function TMyClass_ONE_UsingInterface.fncHelloWorld_ONE: integer;
begin
  result := 123;
end;

function TMyClass_ONE_UsingInterface.GetHelloWorld_ONE: string;
begin
  result := 'hello';
end;

procedure TMyClass_ONE_UsingInterface.prcHelloWorld_ONE;
begin
  // ???
end;

procedure TMyClass_ONE_UsingInterface.SetHelloWorld_ONE(Value: string);
begin
  if (Value = 'Hello') then
    Value := 'World'
  else
    FMyValue := 'WOW China';   // <---
end;

{ TMyClass_TWO_Using_Inheriting_Other_Interface }

procedure TMyClass_TWO_Using_Inheriting_Other_Interface.prcHelloWorld_TWO;
begin
  // "FMyValue" is a "Protected" field on "TMyClass_ONE_UsingInterface", then, it can be accessed on this sub-class (inherited from...)
  if FMyValue = 'World' then     // <---
    FMyValue := 'Hello';
end;

end.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/12 1:41:15
3楼: type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  uMyClasses_Interfaces;

var
  // using the "class"
  MyObj_As_Class_ONE: TMyClass_ONE_UsingInterface;
  MyObj_As_Class_TWO: TMyClass_TWO_Using_Inheriting_Other_Interface;
  //
  // using the "interface"
  MyObj_As_Interf_ONE: IMyInterf_BASE_ONE;
  MyObj_As_Interf_TWO: IMyInterf_BASE_TWO;
  //
  LValue: integer;
  LText : string;

procedure procA;
begin
  // **** TMyClass_ONE_UsingInterface ****
  MyObj_As_Class_ONE := TMyClass_ONE_UsingInterface.Create;
  try
    // procedure
    MyObj_As_Class_ONE.prcHelloWorld_ONE;
    // function
    LValue := MyObj_As_Class_ONE.fncHelloWorld_ONE;
    // property
    MyObj_As_Class_ONE.propHelloWorld_ONE := 'Hello';
    LText          := MyObj_As_Class_TWO.propHelloWorld_ONE;

    // procedure
    // MyObj_As_Class_ONE.prcHelloWorld_TWO;  <--- dont exits for "MyClass_ONE_UsingInterface"
  finally
    MyObj_As_Class_ONE.Free; // class needs "FREE"
  end;
end;

procedure procB;
begin
  // **** TMyClass_TWO_Using_Inheriting_Other_Interface **** //
  MyObj_As_Class_TWO := TMyClass_TWO_Using_Inheriting_Other_Interface.Create;
  try
    // procedure
    MyObj_As_Class_TWO.prcHelloWorld_ONE;
    // function
    LValue := MyObj_As_Class_TWO.fncHelloWorld_ONE;
    // property
    MyObj_As_Class_TWO.propHelloWorld_ONE := 'Hello';
    LText          := MyObj_As_Class_TWO.propHelloWorld_ONE;
    // procedure
    MyObj_As_Class_TWO.prcHelloWorld_TWO;

  finally
    MyObj_As_Class_TWO.Free; // class needs "FREE"
  end;
end;

procedure procC;
begin
  // **** TMyClass_ONE_UsingInterface ****
  MyObj_As_Interf_ONE := TMyClass_ONE_UsingInterface.Create;
  //
  // procedure
  MyObj_As_Class_ONE.prcHelloWorld_ONE;
  // function
  LValue := MyObj_As_Class_ONE.fncHelloWorld_ONE;
  // property
  MyObj_As_Class_ONE.propHelloWorld_ONE := 'Hello';
  LText          := MyObj_As_Class_TWO.propHelloWorld_ONE;

  // procedure
  // MyObj_As_Class_ONE.prcHelloWorld_TWO;  <--- dont exits for "TMyClass_ONE_UsingInterface"

  // Interfaces dont needs "FREE"
end;

procedure procD;
begin
  // **** TMyClass_TWO_Using_Inheriting_Other_Interface **** //
  MyObj_As_Interf_TWO := TMyClass_TWO_Using_Inheriting_Other_Interface.Create;
  // procedure
  MyObj_As_Class_TWO.prcHelloWorld_ONE;
  // function
  LValue := MyObj_As_Class_TWO.fncHelloWorld_ONE;
  // property
  MyObj_As_Class_TWO.propHelloWorld_ONE := 'Hello';
  LText          := MyObj_As_Class_TWO.propHelloWorld_ONE;
  // procedure
  MyObj_As_Class_TWO.prcHelloWorld_TWO;
  //
  // Interfaces dont needs "FREE"
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  LObj_ONE: IMyInterf_BASE_ONE;
  LObj_TWO: IMyInterf_BASE_TWO;
begin
  procA;
  procB;
  procC;
  procD;
  //
  // ********** //
  // "Father" accept        "Child"
  // "Child"  cannot accept "Father"
  //
  // TMyClass_ONE_UsingInterface
  // TMyClass_TWO_Using_Inheriting_Other_Interface
  LObj_ONE := TMyClass_ONE_UsingInterface.Create;
  LObj_TWO := TMyClass_TWO_Using_Inheriting_Other_Interface.Create;
  //
  LObj_ONE := TMyClass_TWO_Using_Inheriting_Other_Interface.Create;
  //
  // LObj_TWO := TMyClass_ONE_UsingInterface.Create;  It cannot be!!!
  {
    IMyInterf_BASE_TWO  has     IMyInterf_BASE_ONE = OK!!!
    IMyInterf_BASE_ONE  NOT HAS IMyInterf_BASE_TWO = NOT OK!!!
  }
  LObj_TWO := TMyClass_TWO_Using_Inheriting_Other_Interface.Create;

end;

initialization

ReportMemoryLeaksOnShutdown := true;

end.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/12 1:54:09
4楼: The use of "Interfaces" allows you to show only what is "strictly necessary" for the user (programmer) of your interfaces!!!

In this way, the new programmer will only know what really matters to his project!!! It is not important to show the "real code" (what was actually abstracted), so you protect your API (or code) so that it is not used improperly or wrongly, avoiding many programming errors (bugs).

That's how the big platforms like Alibaba, Google, Amazon, Microsoft, etc... do it!!!

In the past, it was very common to see a lot of "DLLs" scattered around the system... today, there was a lot of talk about "API"... 

in the end, it's practically the same thing, that is: 
--- all the actual software code was abstracted for more comfortable use by new programmers. Thus, many basic programming errors are avoided!!!

However, an "Interface" is not the solution for everything!!!
It is often necessary to use the "Class"!!!
So, everything in its place!!!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/12 2:09:20
5楼: type
  IMyInterf_THREE = interface(IMyInterf_BASE_TWO)   // <---- Interf_ONE + Interf_TWO inheriting
  end;

  TMyClass_THREE = class(TInterfacedObject, IMyInterf_THREE)

  private
    function GetHelloWorld_ONE: string;
    procedure SetHelloWorld_ONE(Value: string);
    //
  public
    procedure prcHelloWorld_ONE;
    function fncHelloWorld_ONE: integer;
    //
    property propHelloWorld_ONE: string read GetHelloWorld_ONE write SetHelloWorld_ONE;
    //
    procedure prcHelloWorld_TWO;
  end;

  TMyClass_FOUR = class(TMyClass_THREE)
   //  // inheriting all ( Interfaces ONE/TWO/THREE + Class ONE/TWO/THREE implementations)
  end;


... implementation code
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/12 5:04:35
6楼:  inbreak (入侵)
----------
但是缺点也很明显了。
1、性能低下;
2、调整麻烦,就是按住 Ctrl + 函数/过程名,直接跳到 接口的定义。具体的实现还得再慢慢找。
----------

1) The performance should be the same as using "TClassXXXX",.... an "Interface" is just a way to hide the part of the class that you don't want to share with other users (programmers). Just it!!!
If performance is lost, then the class is poorly designed!

2)When you use "CTRL+mouse-click" on an object that uses "Interface", the IDE finds the definition of the interface, and, it's correct!!! Well, you are defining that the interface is the only means that the user (Programmer) has to execute the real code of the class! 
So the "Code-Editor" only knows the "interface", not the class directly!!! == "Interface" = "Hiding real code"
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/3/12 11:39:40
7楼: 接口太好用了。

1. 使用接口,类似于实现多态,但无需继承。

首先要有个概念:为什么要面向对象?其实对象就是把一堆相似的功能的代码,组织到一起。本质是代码的一种组织方式。就好比出纳和会计,都是和钱打交道的,从人的组织上,把他们放一起,装进财务部这个办公室;而写程序的一堆人,都放一起,装进软件部这个办公室;这个就是人的组织。如果把财务的人都放到软件部,别人要报账,都不知道该找谁。

关于接口:
简单说,你有一组函数(也就是一堆可以组织到一起的功能),你可以把它们都写到一个类里面,那就是类的方法。

从多态的角度看,一个狗,有走,跑,叫;一个锚,也有走,跑,跳。因此你搞一个叫做动物的父类,有走,跑,跳这几个类方法,然后狗和猫从这个动物类继承。

但是,如果哪天你写的代码,需要新的功能,无法从动物这个类继承,但同样也要有走,跑,跳,这个功能,咋搞?

这个时候,就可以用接口了。

用了接口,还可以极大降低代码的耦合度。比如,你需要调用走这个功能的地方,它根本无需知道有【狗】这个类,它仅仅只需要调用它的父类就可以了。但它仍然需要知道父类。

如果使用接口,那么,你的代码有几百个单元里面都需要调用【跑】这个函数的地方,仅仅需要调用接口就好了。完全不用知道是哪个类在实现这个接口。这时候,如果你的【跑】这个函数的功能要变,你就完全不用去改动几百个单元里面对应的代码。

这时候,你需要做的,就是增加一个类,实现这个接口,在实现代码里面,对于【跑】有你自己的意思。实现了这个类以后,你仅仅需要改变一个单元:类工厂;而不是需要改变几百个单元。

然后,你那几百个单元里面的关于【跑】的功能就全部统一改变了。

这就是使用接口使得代码耦合度降低,带来的复杂度的大大降低。

2. Delphi 的接口,有内存管理功能,引用为零时,实现接口的对象自动释放。这样就使得复杂程序因为对象忘记释放(程序太复杂,作为程序员你找不到合理的释放对象的位置,想释放都不知道该写在哪里)导致的内存泄露这种事情基本上不会出现。

3. 对象缓冲:基于接口的内存管理,稍微做点修改,你就可以使用把接口存起来的方式,实现自动的对象缓冲。原本接口引用计数为零的时候,对象自动释放,修改为引用计数为零时,对象自动回到缓冲池。使用非常少的代码就能实现这个功能。如果一个对象需要频繁创建和释放,比如1秒钟有几十上百次,你不做缓冲,直接创建和释放,就会发现 CPU 会忙得不得了。而使用对象缓冲,CPU 马上就不忙了。

4. 在二进制上实现多态。前面讲到的用接口实现多态,是源代码一级。如果你把接口单元编译为一个独立的 BPL,其它实现接口的类也编译成独立的 BPL,在二进制这一层,你只要换掉 BPL 就换了实现代码。甚至你的新的 BPL 里面的代码,虽然同样实现了【跑】这个方法,但完全不需要从【动物】类继承,可能是从【财务】类继承的,但只要它实现了同样的接口,就可以。而你的程序调用这个接口方法的部分,不需要重新编译。通过这样的方式,至少你的程序升级、打补丁,就不用全部重装,仅仅只要替换实现接口的 BPL 文件。另外,你的程序还可以实现动态配置,实现相同【跑】方法的多个 BPL 文件同时存在,根据不同的需要,加载不同的 BPL 文件就好了。程序里面其它调用接口方法的地方不用做任何修改,因为它仅仅调用的是接口。但因为加载的是不同的 BPL,最终程序执行结果就不一样。所以这是二进制层面的多态。

使用接口有一大堆好处。暂时一下能想到的就这些。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/3/12 11:40:23
8楼: 至于说【性能底下】,不知道这个话从何说起?
----------------------------------------------
-
作者:
男 zwjchinazwj (蒲石) ★☆☆☆☆ -
普通会员
2023/3/12 20:45:07
9楼: @pcplayer (pcplayer)
“至于说【性能底下】,不知道这个话从何说起?”
从ARC的慢说起。:)
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/3/12 22:55:53
10楼: 接口和 ARC 没什么关系。Delphi 是搞多平台的时候才开始搞 ARC 的。到 10.4 又把 ARC 取消了。但接口引用计数这个,从 Delphi 有了接口就有的。Delphi 支持接口编程是从支持 WINDOWS 的 COM/DCOM 的时候开始的。

基于接口的对象,在接口引用为零时被释放,那个释放代码,是直接写在  TInterfacedObject 这个类里面的。只要你的基于接口的类,是从 TInterfacedObject 这个类继承的,它就会自动释放。
----------------------------------------------
-
作者:
男 roadrunner (roadrunner) ★☆☆☆☆ -
盒子活跃会员
2023/3/13 0:26:14
11楼: 接口是跨语言的,而类, 不管是C++的还是delphi的还是java的,都不能跨语言
----------------------------------------------
-
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2023/3/13 8:36:24
12楼: 我觉得接口最大的好处是解耦, 其次就是跨语言
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
男 doersoft (yixsys.com) ★☆☆☆☆ -
普通会员
2023/3/13 8:36:29
12楼: 继承的价值主要在于:解决代码的复用性和可维护性
接口的价值主要在于:设计、设计好各种规范(方法),让其他类去实现这些方法
接口比继承更加灵活
继承是满足is - a 的关系,而接口只需满足like-a关系
  
接口简单的理解可认为是一个抽象类,我们先定义一个抽象类和接口来对比之间的异同,代码如下:

 type
  IFormattedNumber = interface          //定义接口
    function FormattedString: string;
  end;
 
  TFormattedNumber = class          //定义抽象类
  public
    function FormattedString: string; virtual; abstract;
  end;          
  上面定义了一个接口IFormattedNumber和抽象类TFormattedNumber,从delphi方法上来说,都不能直接实例化,接口是通过类来实现的,而抽象类则是通过其派生类来实现其具体的功能。抽象类与接口的不同我理解有以下几点:

  (一)、接口通过Interface关键字定义,而类则通过Class关键字定义,接口以“I”前缀命名,抽象类则“T”前缀命名;

  (二)、接口直接或者间接派生自IUnKnown,而类则派生自TObject;

  (三)、接口不能直接范围,只能是public,但不要声明;

   (四)、接口不能声明变量,只能包含函数或者过程;

  (五)、接口声明的函数和过程从概念上讲是virtual类型,但不能直接使用virtual关键。 

  接口定义好后就不要修改,如果需要修改,一般的做法是定义新接口,这种做法的目的是保证调用者因为修改接口,而修改调用程序。如果需要增加功能,可以直接从父接口直接派生,如为IFormattedNumber增加SetValue(AValue:Integer)过程我们可以以下代码实现声明:

type
    IFormattedNumber2 = Interface(IFormattedNumber)
        procedure SetValue(AValue);
    end;

  二、接口的声明和实现   
  接口声明和实现很简单,请看下面代码:

unit Unit2;
 
interface
 
uses
  SysUtils;
 
type
  IFormattedNumber = interface          //接口声明
    ['{F9E8F5DE-781B-4B5B-B78A-0F88CF50E53F}'] {GUID,Alt+Shift+G快捷键生成}
    function FormattedInteger: string;
  end;
  TFormattedNumber=class(TObject,IFormattedNumber)          //实现接口类
  private
    FValue:Integer;
  public
    constructor Create(AValue:Integer);
    destructor destroy;override;
    function FormattedInteger: string;     //实现接口函数FormattedInteger;
  end;
 
implementation
constructor TFormattedNumber.Create(AValue:Integer);
begin
  inherited Create;
  FValue:=AValue;
end;
destructor TFormattedNumber.destroy;
begin
  inherited destroy;
end;
function TFormattedNumber.FormattedInteger:string;
begin
  Result:=IntToStr(FValue);
end;
 
end.
  接口只是声明功能的地方,具体由类来实现的,到这里我们理解"接口简单的理解可认为是一个抽象类"这句话了吧!
----------------------------------------------
delphi|vue|golang yixsys|yixerp|mes|srm
作者:
男 powerpcer (小强) ★☆☆☆☆ -
普通会员
2023/3/13 8:42:21
13楼: abstract class : 有 上下/繼承 關係。
interface : 無 上下/繼承 關係,只是剛好大家應該共有。
interface 一個例子, 例如 CRYPTO 的HASH FUNCTION,SHA 和MD5 和...
它們適用INTERFACE 而不是abstract class.

這樣講夠簡單了吧。
所以才會有:
2、调整麻烦,就是按住 Ctrl + 函数/过程名,直接跳到 接口的定义。具体的实现还得再慢慢找。

但和PERFORMANCE 無關!!
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/3/13 10:01:42
14楼: 上面提到接口可以理解为抽象类。


当年学 COM 的时候,说 COM 的接口,在 C++ 里面就是抽象类,在 Delphi 里面采用接口来定义。

在 C++ 里面,类继承可以有多继承,一个子类可以有两个父类。Delphi 是单继承的,一个子类只能有一个父类。那么,如果需要多个父类(聚合两个父类的方法)怎么办?在 Delphi 里面就可以搞接口来实现,如下写法:

TMyObject = class(TInterfacedObject, IMyTest1, IMyTest2)
----------------------------------------------
-
作者:
男 tiez (骑牛夜旅) ★☆☆☆☆ -
普通会员
2023/3/14 11:50:10
15楼:   delphi中的interface不同的人会基于不同的理由使用它。但有的理由带来的使用方式会使它显得很难用,而另一些方式却显得和传统的对象管理方式差别不大。

  OOP开发建议我们用某分类法去构造类及其子类去容纳不同的方法代码去映射现实对象。在C++中是支持多继承的。delphi中使用的是单继承,这使得我们无法仅使用类继承的方法去表达现实生活多种多样的分类法。这时,我们可以使用一个基础的主干分类法来构造类继承基础,使用interface来实现基于其它分类法的方法归纳表达。

  不可不提的是很多人提到delphi的interface必然提到其引用计数和自动销毁机制。进而不是基于扩充必要的分类法的原因,而是基于生存周期管理的原因去使用interface。我建议大家在实际开发中要避免采用这种视角,除了基于学Xi的目的开发的试验项目除外。

  delphi提供的基础类型如TInterfacedObject、TInterfacedPersistent、TComponent等都对接口的引用计数做了不同的实现,这些实现可能以不同的方式实现了利用不同机制的生存周期管理。多数delphi开发人员对于对象生存周期的管理已建立了相应的思路,有较丰富的经验。在系统开发时增加一套完全不同的对象生存周期管理机制是非常容易造成混乱的,尤其是在多线程开发的情况下。

  使用interface时最简单的使用方法是利用它在原有的体系中增加额外的分类管理和操作方法,而避免它的生存周期管理功能。就是以对象管理为核心,保持对象指针的有效性,在手动销毁对象时保证所有对接口的引用都已失效或取消接口引用机制的生存周期维护功能。

  尽量采用临时接口引用是一个好办法。如须在其它对象内保存接口指针,保证这些对象的生存周期短于接口管理者的生存周期。在接口内包含销毁通知的回调,让使用方提前取消引用指针的保存也是一个好办法。

  实现接口的对象基类尽量不要使用包含了大量高等级实现的类型。delphi的一些包含了默认接口实现的高等级类自身生存周期管理方式非常复杂,可能会带来不期望的后果。

  楼主提到的反向找接口实现类的代码的问题,这不仅在delphi中是这样的,类似java等单根对象的都是一样的表现。这是因为interface相当于一个顶级的分类,就像你不能在delphi中通过基类的方法直接转到子类的实现代码中一样,哪怕这个存放基类的指针实际存放的就是其子类。 
  想做到你所说的特征,只能由编辑器利用类型反射去找到相应代码了,这和语言特征无关,而取决于IDE的实现。

  interface作为一个出现得比较早的概念,它的一些应用特征在泛型出现后又被其在一些场合取代了,应用面逐渐收窄。可以说,参数化类、类成员、泛型,在很多地方瓜分了interface的地盘。
  
  在java、kotlin开发中,interface比delphi中应用的广泛一些,这不是说明interface本身有什么不同,而是它们生存周期模式是一致的。另外kotlin在interface中可以为方法设置默认实现可能也是一个进步。
----------------------------------------------
-
作者:
男 wiseinfo (wisienfo) ★☆☆☆☆ -
普通会员
2023/3/15 3:08:32
16楼: 从入门到精通, 推荐万一老师
https://www.cnblogs.com/del/category/147315.html
----------------------------------------------
-
作者:
男 kwer (★★★★★) ★☆☆☆☆ -
普通会员
2023/3/15 8:32:53
17楼: 我同意 @pcplayer 观点,,,接口是规范,是标准,是统治者制定的游戏规则,允许出现N个版本都能在他的势力范围内运行。。。我这么多年一次都没有用过接口,因为我做的都是个人玩意,也没想过别人的程序跑到我的程序上面运行。
----------------------------------------------
==========-==========-==========-==========-==========
     多隆, 给我备一匹最快的马, 我有事要走先~~~
==========-==========-==========-==========-==========
作者:
男 zhyhero (zhyhero) ★☆☆☆☆ -
盒子活跃会员
2023/3/15 9:30:33
18楼: 依赖注入

Dependency Injection in Delphi
----------------------------------------------
z@S7
作者:
男 hawke2e (hawke2e) ★☆☆☆☆ -
普通会员
2023/3/19 22:28:28
19楼: 你就记住这些知识点就够了,以后在使用中自然会加深理解,这些都是次要的东西。
软件工程,无论是1、2个人开发还是1万个人开发,其核心点用个类比就明白了:
同样一幅画,如果画在张A4纸上,画的好不好其过程有没有问题,一般一眼就能看出来。
然后如果要画在跟地球面积那样大的纸张(假设能做到),那唯一策略就是把画分成若干块,控制每块的绘画质量从而控制最终结果。
最终画得不好、超预算,那肯定是没把成本放在最要紧的地方。
所以,类、接口、freeandnil等这些写得优不优雅,用得恰不恰当,有没有侵入式设计,等等,都不是要紧的事。
我记得,知乎上有个人说他写了段代码开源,被别人跳出100多个毛病,以为自己学到真经,我笑了。
大公司的所谓高手,所谓优雅,所谓大道至简,所谓用设计降低熵,都是在宽松成本下的自我安慰;试下把成本砍掉10份九,你就知道这些都是花拳绣腿。
----------------------------------------------
软件是什么,相信很多人都说不清。
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2023/3/20 19:50:50
20楼: 做程序,大抵有三类:底层、中层和高层。其实大部分程序员写的是中层和和高层应用。
接口是一个要慎用的技术,它适用于中层偏底层。它适用于写框架、类库和组件体系结构型场景,如果要在项目级程序中大量使用接口,你必须确信自己是功力非常深厚的大师级,否则可能出现难以解决的内存管理问题,收益与付出会不对等,而这些问题用常规方法实现,本来是可以避免的。
在delphi和lazarus里,接口一个重要功能是:从dll、so里导出类,如果不使用接口,你只能导出函数。
其实在中高层项目中,我们可以使用泛型、匿名和回调,去解决接口需要解决的大部分问题。
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行41.99219毫秒 RSS