2015-01-24 11 views
4

Я следующий беглом описания интерфейса и класса, который реализует этот интерфейс:свободный интерфейс с наследованием в Delphi

type 
    IDocWriter = interface 
    ['{8CB5799A-14B1-4287-92FD-41561B237560}'] 
    function Open: IDocWriter; 
    function Close: IDocWriter; 
    function Add(const s: string): IDocWriter; 
    function SaveToStream(Stream: TStream): IDocWriter; 
    end; 

    TDocWriter = class(TInterfacedObject, IDocWriter) 
    public 
    function Open: IDocWriter; 
    function Close: IDocWriter; 
    function Add(const s: string): IDocWriter; 
    function SaveToStream(Stream: TStream): IDocWriter; 
    end; 

{ TDocWriter } 

function TDocWriter.Open: IDocWriter; 
begin 
    Result := Self; 
    // DoOpen 
end; 

function TDocWriter.Close: IDocWriter; 
begin 
    Result := Self; 
    // DoClose 
end; 

function TDocWriter.Add(const s: string): IDocWriter; 
begin 
    Result := Self; 
    // DoAdd 
end; 

function TDocWriter.SaveToStream(Stream: TStream): IDocWriter; 
begin 
    Result := Self; 
    // DoSaveToStream 
end; 

И я могу использовать выше код следующим образом:

var 
    Stream: TStream; 
    ... 
    TDocWriter.Create 
    .Open 
    .Add('abc') 
    .Close 
    .SaveToStream(Stream); 

Я должен простираться выше интерфейс, добавив функцию SaveToString.

Я не хочу добавлять этот метод к исходному интерфейсу IDocWriter, потому что это недопустимый метод для всех реализаций интерфейса. Так что я сделал следующий

type 
    IStrDocWriter = interface(IDocWriter) 
    ['{177A0D1A-156A-4606-B594-E6D20818CE51}'] 
    function SaveToString: string; 
    end; 

    TStrDocWriter = class(TDocWriter, IStrDocWriter) 
    public 
    function SaveToString: string; 
    end; 

{ TStrDocWriter } 

function TStrDocWriter.SaveToString: string; 
begin 
    Result := 'DoSaveToString'; 
end; 

Для того, чтобы использовать IStrDocWriter интерфейс я должен написать код

var 
    Writer: IDocWriter; 
    s: string; 

    Writer := TStrDocWriter.Create 
    .Open 
    .Add('abc') 
    .Close; 
    s := (Writer as IStrDocWriter).SaveToString; 

Но я хотел бы, чтобы иметь возможность использовать его без необходимости объявить Writer переменными, что-то вроде следующий код (который, разумеется, не может быть скомпилирован)

s := TStrDocWriter.Create 
    .Open 
    .Add('abc') 
    .Close 
    .SaveToString; // Undeclared identifier SaveToString 

Есть ли способ достичь этого?

Любые изменения в интерфейсах и классах приемлемы (за исключением, очевидно, объединения этих двух интерфейсов в один).

+1

Вся конструкция выглядит неправильно для меня. Свободно это просто так плохо! –

+0

Простите мое любопытство, но есть ли этот интерфейс v. Безоговорочное требование самостоятельно или оно вытекает из фактического бизнес-требования и, если да, то как? – MartynA

+1

@MartynA это причиняет себе причину. Интерфейсы, потому что он подсчитан и устраняет необходимость в блоках try..finally. Свободно, потому что он устраняет необходимость объявления переменных и делает код более читаемым, когда у вас длинная цепочка. Его можно использовать inline в противном случае грязный код, который вы обычно можете использовать при создании документа или отчета. Представьте себе TTextDocWriter, TRichTextDocWriter, TPdfDocWriter, TMetafileDocWriter ... –

ответ

4

Вы можете написать это:

s := (TStrDocWriter.Create 
    .Open 
    .Add('abc') 
    .Close as IStrDocWriter) 
    .SaveToString; 

Нет, не очень приятно это. Эти две идиомы, плавные интерфейсы и наследование просто не смешиваются.

+0

Выглядит достаточно хорошо по назначению. Я знаю, что свободное владение не работает с наследованием, но ... –

+3

Похоже, что это отличный пример того, зачем нужны интерфейсные помощники в Delphi. –

+0

@Stefan Знаете ли вы, если есть отчет QC/QP для помощников интерфейса –

 Смежные вопросы

  • Нет связанных вопросов^_^