【问题标题】:Is it possible to add setter for inner(nested) fields in dart?是否可以在飞镖中为内部(嵌套)字段添加设置器?
【发布时间】:2020-03-14 20:47:53
【问题描述】:

在 dart 中,当字段的值发生更改时,我们可以执行一些代码,例如

class Name{
  String fname;
  String lname;
}
class Person extends ChangeNotifier{
  Name _name = Name();
  set name(Name n){
    notifyListeners();
    _name = n;
  }
  get name=>_name;
}

//inside main() 
Person p = Person();
p.name = Name();

我希望能够在设置内部字段时执行类似的操作。比如在做的时候

p.name.fname ="FooBar";

但我希望能够从 Person 类中做到这一点。

因为我在 Person 类中扩展 ChangeNotifier。我想打电话

notifyListeners()

在 Name 类中无法访问。这是我想出的最好的方法

Name newName = Name(p.name); //copy constructor
newName.fname = "Foo Bar";
p.name = newName;

有没有更好的办法?

【问题讨论】:

    标签: dart


    【解决方案1】:

    您能做什么取决于您如何约束 API。

    如果Name 对象通常由第三方代码创建并传递,并且在存储在Person 对象中时预计会保留其身份,那么您无能为力。所以我不会那样设计 Person 对象。

    相反,我会说Person 对象的Name 对象与该对象相关联,设置Personname 与设置两个名称部分相同。

    例子:

    class Person {
      _PersonName _name;
      Person(...) : ... {
        _name = _PersonName(this);
      }
      ...
      void set name(Name name) {
        _name.fname = name.fname;
        _name.lname = name.lname;
        notifyListeners();
      }
      Name get name => _name;
    }
    
    class _PersonName extends Name {
      final Person _owner;
      _PersonName(this._owner);
      void set fname(String fname) {
        super.fname = fname;
        _owner.notifyListeners();
      }
      void set lname(String lname) {
        super.lname = lname;
        _owner.notifyListeners();
      }
    }
    

    这样做的缺点是提取的_PersonName 永远链接到Person 对象,即使您尝试编写不同的Name 对象也是如此。

    另一种选择是在每个商店创建一个新的_PersonName 新名称对象,然后将旧对象与Person 分离:

    class Person {
      _PersonName _name = _PersonName;
      Person(...) : ... {
        _name = _PersonName(this, null, null);
      }
      void set name(Name name) {
        _name.owner = null;
        _name = _PersonName(this, name.fname, name.lname);
        notifyListeners();
      } 
      Name get name => _name;
    }
    class _PersonName extends Name {
      Person _owner;
      _PersonName(this._owner, String fname, String lname) {
        super.fname = fname;
        super.lname = lname;
      }
      void set fname(String fname) {
        super.fname = fname;
        owner?.notifyListeners();
      }
      void set lname(String lname) {
        super.lname = lname;
        owner?.notifyListeners();
      }
    }
    

    这种方法的行为主要类似于名称对象的普通存储,除非你这样做:

    var p = Person(); var n = 名称(); p.name = n; 打印(相同(n,p.name)); // 假的?

    您不会保留存储到 Person 对象中的 Name 对象的身份。 没有办法这样做,而且还改变了使用person.name.fname = ...直接在名称上设置字符串的行为,所以必须牺牲一些东西。

    【讨论】:

    • 这绝对看起来比我的方法更好。但老实说,一开始很难理解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多