我经常看到以下被描述为实现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”方法时,我们获得了对 private var =>的引用。封装破裂了。
即使我们没有set方法,我们也可以修改privar var! 将其设置为私有的目的是什么?
我发现的唯一解决方案是在get方法中返回“_someVar”的克隆,但我从未在任何示例中看到过这种情况。 所以我觉得我在这里失去了一些东西。
您是从getter返回克隆对象还是只接受封装中断?
修改 我理解set和get方法是如何工作的,我理解它们的好处。 当我们通过引用返回它时,我要求在私有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方法,我们也会从外部更改我们的私有变量,并且无法控制。
答案 0 :(得分:4)
使用get / set函数时,您正在控制对成员变量的访问。例如,如果您希望变量从外部“只读”,但可以从类实例中编辑,则可以创建一个get函数,以便可以从外部读取但不创建set函数。这与使用私有const不同,因为它必须立即声明,并且永远不能从任何地方更改。
同样,使用这些功能可以让您创建用于设置属性的副作用。例如:
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来做这项工作......你只是做广告,你自己可以做到。
答案 1 :(得分:1)
您可以在其所属的类中修改私有变量,但不能从该类外部修改它。
使用getter和setter方法可以让你在课堂上获得更多的力量(作为开发人员)。
您的应用程序将会增长,并且在某些时候您可能希望您的类能够在检索它之前或在设置它之前对某个值执行某些操作。您可能还希望您的类能够在每次设置值时调用方法。这样的事情,当你有getter / setter方法时你很容易实现。
此外,正如TheDarkIn1978所说,将其中一种方法排除在外,可以使变量成为只读或只读,这对封装来说是一个巨大的好处。
答案 2 :(得分:0)
如果我需要知道是否修改了该变量以便更改其他内容,我经常使用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;
}
答案 3 :(得分:0)
上面的代码与简单编写完全相同:
public var someVar:SomeClass;
但是,如果您想要将此变量设置为只读或只写,则可以分别为私有变量提供公共getter或public setter。
此外,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;
}
答案 4 :(得分:0)
如果要进行封装,则不应提供对复杂对象的直接访问(由ref传递)。你应该看看你希望其他类可以用你的'SomeClass'做什么。如果您确实需要传递整个类并且不希望它是ref,那么添加一个克隆方法。如果您只是希望其他类更新属于'SomeClass'的某些数据,则为该数据提供setter并将其直接应用于'SomeClass'实例。它确实需要更多代码,但将实现封装类的目标。