AS3 中的 get/set 方法和封装

发布于 2024-11-15 17:31:52 字数 1357 浏览 2 评论 0原文

我经常看到以下描述为实现 get/set 方法的“正确”方法:

public class Foo {
    private var _someVar:SomeClass;

    public function get someVar():SomeClass {
       return _someVar;
    }

    public function set someVar(newValue:SomeClass):void {
      _someVar = newValue;
    }
}

现在,因为 AS3 始终返回对 Object 类的引用,所以当我们使用“get”方法时,我们获得对 的引用私有 var =>封装被破坏。

即使我们没有 set 方法,我们也可以修改 privar var ! 那么设置为private的目的是什么呢?

我发现的唯一解决方案是在 get 方法中返回“_someVar”的克隆,但我从未在任何示例中看到过这种情况。 所以我想我在这里失去了一些东西。

您是从 getter 返回克隆对象还是只是接受封装的中断?

编辑 我了解 set 和 get 方法的工作原理,也了解它们的好处。 当我们通过引用通过 getter 返回它时,我要求中断我们的私有 var 中的“私有”访问(如果我们的 var 类型为 Number、String、int 等,AS3 总是返回)按值,而不是参考,所以我们在这里没有问题)。 也许不是封装被破坏了,因为如果没有 setter 方法,我们就无法设置属性。但我们可以修改它!

看这个例子:

public class Foo {
    private var _someVar:Array; // note that this is a Object (not Number, String, etc)

    public function Foo(){
        _someVar = ['don't touch this!'];
    }

    public function get someVar():SomeClass {
       return _someVar;
    }

    // note that we don't have a setter

}


var f:Foo = new Foo(); 
var a:Array = f.someVar;
trace(a[0]); //  'don't touch this!'
a[0] = 'why not?'; 
trace(f.someVar[0]); // 'why not' 

所以,我们从外部改变我们的私有变量,并且不受控制,即使我们没有 setter 方法。

I've often seen the following described as the "correct" way of implementing get/set methods:

public class Foo {
    private var _someVar:SomeClass;

    public function get someVar():SomeClass {
       return _someVar;
    }

    public function set someVar(newValue:SomeClass):void {
      _someVar = newValue;
    }
}

Now, because AS3 is returning always references to Object classes, when we use the "get" method we obtain a reference to our private var => encapsulation is broken.

Even if we don't have a set method we can modify the privar var !
What is the purpose of setting it as private then?

The only solution that I found to this is to return a clone of "_someVar" in our get method, but I've never seen this in any example.
So I think I'm losing something here.

Are you returning a clone object from your getters or you just accepting the break in encapsulation?

EDIT
I understand how set and get methods works, and I understand the benefits of them.
I'm asking for the break of "private" access in our private var when we return it with a getter by reference (if our var is of type Number, String, int, etc AS3 is returning always by value, not reference, so we don't have problem here).
Maybe is not the encapsulation which is broken, because we can't set the property without a setter method. But we can modify it !

See this example:

public class Foo {
    private var _someVar:Array; // note that this is a Object (not Number, String, etc)

    public function Foo(){
        _someVar = ['don't touch this!'];
    }

    public function get someVar():SomeClass {
       return _someVar;
    }

    // note that we don't have a setter

}


var f:Foo = new Foo(); 
var a:Array = f.someVar;
trace(a[0]); //  'don't touch this!'
a[0] = 'why not?'; 
trace(f.someVar[0]); // 'why not' 

So, we are changing our private var from outside, and without control, even when we don't have a setter method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

白馒头 2024-11-22 17:31:52

当您使用 get/set 函数时,您正在控制对成员变量的访问。例如,如果您希望变量从外部“只读”,但可以从类实例内部编辑,则可以创建一个 get 函数,以便可以从外部读取它,但不要创建 set 函数。这与使用私有常量不同,因为它必须立即声明并且永远不能从任何地方更改。

同样,使用这些函数可以让您在设置属性时产生副作用。例如:

public function set foo(value:*):void{
    _foo = value;
    this.dispatchEvent(new Event("fooSet")); 
    // setting foo alerts interested parties
    // that the value of foo has changed
    // without them having to poll foo.
}

编辑:因为您已将问题更新得更具体,所以这是我自己的更新。

你通常不会这样做。如果您试图保护变量本身,那么您将不会直接提供对它的访问。这样做违反了“得墨忒尔法则”。对于数组的具体示例,您可能会执行以下操作:

private var _someArray = [true,false];

function get someArray():Array{
    return _someArray.slice(); // Returns a clone of the original array.
}

作为一个不同的示例,使用理论上的复杂对象...

private var _someObject:SomeObject;

function get someObject():SomeObject{
    return _someObject; // "Wrong."  It breaks the law of demeter.
}

////// instead, you would do this.....

function get getSomeObjectsInt():int{
    return _someObject.foo; // where .foo is an int
} 


////// or this....

function doStuffWithFooObject():Boolean{
   return _someObject.doSomething(); // where doSomething returns a boolean;
}


///// or this.....

function performActionOnData(pData:String):String{
    return _someObject.someActionWithString(pData); 
}

最后一个很有趣,因为您不需要向世界公开您正在使用 SomeObject去做这项工作……你只是在宣传你自己可以做到。

You are controlling access to the member variable when you use get/set functions. For example, if you want the variable to be "read-only" from the outside, but editable from within the class instance you make a get function so that it can be read from outside but do NOT create a set function. This is different from using a private const, because that must be declared immediately and can never be changed from anywhere.

Similarly, using these functions can allow you to create side-effects for setting the property. For instance:

public function set foo(value:*):void{
    _foo = value;
    this.dispatchEvent(new Event("fooSet")); 
    // setting foo alerts interested parties
    // that the value of foo has changed
    // without them having to poll foo.
}

EDIT : Because you've updated the question to be more specific, here's an update of my own.

You normally would NOT do that. If you're trying to protect the variable itself, then you won't offer access to it directly. Doing that breaks "the law of Demeter". For your specific example with the array, you might do something like this:

private var _someArray = [true,false];

function get someArray():Array{
    return _someArray.slice(); // Returns a clone of the original array.
}

As a different example, using a theoretical complex object...

private var _someObject:SomeObject;

function get someObject():SomeObject{
    return _someObject; // "Wrong."  It breaks the law of demeter.
}

////// instead, you would do this.....

function get getSomeObjectsInt():int{
    return _someObject.foo; // where .foo is an int
} 


////// or this....

function doStuffWithFooObject():Boolean{
   return _someObject.doSomething(); // where doSomething returns a boolean;
}


///// or this.....

function performActionOnData(pData:String):String{
    return _someObject.someActionWithString(pData); 
}

That last one is interesting because you don't need to expose to the world that you're using SomeObject to do the work... you're just advertising that you yourself can do it.

小女人ら 2024-11-22 17:31:52

您可以从私有变量所属的类内部修改它,但不能从该类外部修改它。

拥有 getter 和 setter 方法可以让您(作为开发人员)对类拥有更多权力。

您的应用程序将会增长,在某些时候您可能希望您的类能够在检索值或设置值之前对值执行某些操作。您可能还希望您的类每次设置值时都能够调用方法。当你有 getter/setter 方法时,你可以轻松实现类似的事情。

此外,正如 TheDarkIn1978 所说,保留其中一种方法可以使变量变为只写或只读,这对于封装来说是一个巨大的好处。

You can modify the private variable from within the class it belongs to, but you can't modify it from outside that class.

Having getter and setter methods gives you more power (as a developer) over the class.

Your application will grow and at some point you may want your class to be able to do something with a value before it retrieves it or before sets it. You may also want your class to be able to call a method every time it sets a value. Things like that, you can easily achieve when you have getter / setter methods.

Additionally, as TheDarkIn1978 says, leaving one of the methods out, could make the variable write-only or read-only which would be of a huge benefit to encapsulation.

硬不硬你别怂 2024-11-22 17:31:52

如果我需要知道该变量是否已被修改以更改其他内容,我经常使用 getter 和 setter。

例如,如果我有 :

public var prop : Number;
private var prop2 : Number;

并且我希望 prop2 随时 = prop + 10,我不知道何时更新 prop2,但我可以这样做:

private var _prop : Number;
private var _prop2 : Number;

public function set prop(newValue : Number):void {
  _prop = newValue;
  _prop2 = prop + 10;
}

I often use getters and setters if I need to know if that variable has been modified in order to change other things.

For example if I would have :

public var prop : Number;
private var prop2 : Number;

and I want that prop2 to be at any time = prop + 10, I wouldn't know when to update prop2, but I could do something like this:

private var _prop : Number;
private var _prop2 : Number;

public function set prop(newValue : Number):void {
  _prop = newValue;
  _prop2 = prop + 10;
}
定格我的天空 2024-11-22 17:31:52

上面的代码与简单的编写完全相同:

public var someVar:SomeClass;

但是,如果您想使该变量只读只写,您将提供一个公共getter或分别为私有变量提供公共设置器。

此外,setter 和 getter 函数允许您管理传递的参数、触发事件等。例如,假设您有一个变量 mySmallNumber:Number ,它只接受小于 10 的值:

private var mySmallNumberProperty:Number;

public function set mySmallNumber(value:Number):void
     {
     if     (value < 10)
            mySmallNumberProperty = value;
            else
            throw new ArgumentError("mySmallNumber must be less than 10");
     }

public function get mySmallNumber():Number
     {
     return mySmallNumberProperty;
     }
  • 请不要不要因为我不遵守下划线前缀的使用而责备我。这是风格问题。虽然它是“标准”,但我也认为它非常丑陋。

the code above is exactly the same as simply writing:

public var someVar:SomeClass;

if, however, you wanted to make this variable read-only or write-only, you would supply a public getter or public setter for the private variable respectively.

in addition, setters and getter functions allow you to manage passed parameters, fire off events, etc. for example, let's assume you have a variable mySmallNumber:Number that should only accept values less than 10:

private var mySmallNumberProperty:Number;

public function set mySmallNumber(value:Number):void
     {
     if     (value < 10)
            mySmallNumberProperty = value;
            else
            throw new ArgumentError("mySmallNumber must be less than 10");
     }

public function get mySmallNumber():Number
     {
     return mySmallNumberProperty;
     }
  • please don't lash out at me for not conforming to the use of the underscore prefix. it's a matter of style. while it's "standard" i also think it's super ugly.
迷你仙 2024-11-22 17:31:52

如果您要进行封装,那么您不应该提供对复杂对象的直接访问(通过 ref 传递)。您应该看看您期望其他类能够使用您的“SomeClass”做什么。如果您确实需要传递整个类并且不希望它成为引用,则添加一个克隆方法。如果您只是希望其他类更新属于“SomeClass”的某些数据,请为该数据提供设置器并将其直接应用于“SomeClass”实例。它确实需要更多代码,但将实现封装类的目标。

If you are going for encapsulation then you shouldn't provide direct access to complex objects (passed by ref). You should look at what it is you expect other classes to be able to do with your 'SomeClass'. If you really need to pass a whole class and don't want it to be a ref, then add a clone method. If you just expect other classes to update some data that belongs to 'SomeClass' the provide setters for that data and apply it directly to the 'SomeClass' instance. It does require more code, but will accomplish the goal of encapsulating your class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文