如何在Dart中模拟受保护的方法?

时间:2015-02-05 17:46:23

标签: dart

(在办公室听到,我们认为其他人会受益)

假设我在库中有一个基类,它提供了一些基本功能,但是它们是由库用户派生的。

例如,我有一个抽象的Greeting类。子类表示特定类型的问候语,如HighFiveGreeting或HugGreeting等等。 Greeting为子类提供了一些实用函数,例如sendGreeting()。我不希望这些类的用户调用sendGreeting()

这可能吗? Dart中有更好的成语吗?

library greeting;

abstract class Greeting {
   void sendGreeting(GreetingEvent event) { ... }
}

library custom_greeting;
import 'greeting.dart';

class HugGreeting extends Greeting {
   // code here uses sendGreeting()
}

library main;
import 'custom_greeting.dart';

var hug = new HugGreeting();
hug.sendGreeting(...); // should not compile

6 个答案:

答案 0 :(得分:8)

我相信没有办法做到这一点,但是FWIW,这似乎是一种组合比继承更可取的情况:

class GreetingSender {
    void sendGreeting(GreetingEvent);
}

class HugGreeting {
    GreetingSender _sender;
    HugGreeting(this._sender);

    void hug() {
        // use _sender.sendGreeting()
    }
}

涉及调用在超类中实现的受保护方法的每个设计都有相应的设计,其中超类被通过构造函数注入的接口替换,并且我还没有遇到这样的情况。改善事情。

答案 1 :(得分:8)

与陈述here一样,现在meta package

中有@protected个注释

我很想知道为什么省略BTW语言中的public | private | protected关键字...:'(

答案 2 :(得分:3)

我遇到了同样的问题,但有人提出了以下解决方案,这对我有用。我将用一个简短的例子来证明:

library view;

abstract class View {
  factory View({HtmlElement host}) = ViewImpl;

  void activate() {
  }
}

abstract class ViewImpl implements View {
  ViewImpl({this.host});

  @override
  void enable() {
    host.classes.remove('disabled');
  }
}

在另一个图书馆:

library button; // notice, this is another library

abstract class Button extends View {
  factory Button({String title, HtmlElement host}) = ButtonImpl; // The magic happens here!
}

class ButtonImpl extends ViewImpl implements Button {
  String title; // voila, a protected property

  ButtonImpl({this.title, HtmlElement host}) : super(host: host);
}

你可以像这样使用它:

final button = new Button(title: "Cancel", host: element);

button.title // => cannot access!

此外,您可以访问受保护的字段,例如单元测试:

// Instantiate the *Impl class to side-step the protection.
final button = new ButtonImpl(title: "Cancel", host: element);
expect(button.title, equals("Cancel"); // => it works!

简而言之,您在Impl类中隐藏了“受保护”方法。您可以在不同的库中自由扩展实现。

希望这有帮助。

答案 3 :(得分:1)

你可以利用图书馆作为隐私的边界来做类似的事情,如下所示:

library greetings;

abstract class Greeting {
   void _sendGreeting(String greeting) => print(greeting);
}

class HugGreeting extends Greeting {
  void sendHug() => _sendGreeting("Hug");
}

在您的主文件中:

import 'greetings.dart';

HugGreeting hug = new HugGreeting();
hug.sendHug();

这样,只有从Greeting 扩展的类驻留在同一个库中才能访问低级_sendGreeting()方法。

答案 4 :(得分:0)

这将调用者限制为子类以及可以访问这些子类的私有成员的所有内容。

**图书馆问候语

class GreetingEvent {
  final message;
  GreetingEvent(this.message);
  toString() => message;
}

abstract class Greeting {
  // The sub class has to pass a method to the super constructor
  // which allows to set a private field in the sub class.
  Greeting(Function setProtected) {
    // passes "this" so the passed static method has an instance
    // context
    setProtected(this, new GreetingProtected(this));
  }

  // protected
  void _sendGreeting(GreetingEvent event) {
    print(event);
  }
}

// This class provides access to protected members of Greeting
// by just forwarding calls
class GreetingProtected {
  // protected
  final _greeting;
  GreetingProtected(this._greeting);

  void sendGreeting(GreetingEvent event) => _greeting._sendGreeting(event);
}

** library custom_greeting

library custom_greeting;

import 'greeting.dart';

class HugGreeting extends Greeting {
  // the reference to the 
  GreetingProtected _protected;
  // pass the method to the super constructor which can 
  // assign the protected-forwarder
  HugGreeting() : super(_setProtected);

  // Method passed to the super constructor to pass
  // the protected-forwarder
  // Has to be static so it can be passed in the constructors
  // super call.
  static _setProtected(HugGreeting greeting, GreetingProtected protected) =>
      greeting._protected = protected;

  void someMethod() {
    // code here uses sendGreeting()
    _protected.sendGreeting(new GreetingEvent('someMethod'));
  }
}

**主

library main;
import 'custom_greeting.dart';
import 'greeting.dart';

void main() {
  var hug = new HugGreeting();
  //hug.sendGreeting(new GreetingEvent('someMessage'));
  // should not compile => and doesn't
  hug.someMethod();
}

答案 5 :(得分:-1)

为什么不使用几乎标准的前缀_将功能标记为私有或受保护?

我认为你不应该完全阻止对私人或受保护功能的访问。当然,让用户知道不需要访问,但你不应该阻止它。就在今天,我在dart-sdk中发现了一个错误。我可以覆盖错误的函数并仍然使用类的其余部分,但是类被标记为私有...我需要将类复制回我的应用程序中......但我很幸运,因为它不依赖在其他任何事情上,但我记得在c#中为listview做了类似的事情,我最终重新创建了包含数百个私有类的完整库,只是为了做一个小改动。

library greeting;

abstract class Greeting {
   void _sendGreeting(GreetingEvent event) { ... }
}
library custom_greeting;
import 'greeting.dart';

class HugGreeting extends Greeting {
   // code here uses _sendGreeting()
}
library main;
import 'custom_greeting.dart';

var hug = new HugGreeting();
hug._sendGreeting(...); // should compile, maybe with a warning...