методы get / set и инкапсуляция в AS3 - PullRequest
4 голосов
/ 17 июня 2011

Я часто видел следующее, описанное как «правильный» способ реализации методов 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 всегда возвращает ссылки на классы объектов, когда мы используем "метод "get", мы получаем ссылку на нашу приватную var => инкапсуляцию.

Даже если у нас нет метода set, мы можем изменить privarвар!Какова цель сделать его закрытым?

Единственное решение, которое я нашел, - это вернуть клон "_someVar" в наш метод get, но я никогда не видел этого ни в одном примере.Так что я думаю, что здесь что-то теряю.

Вы возвращаете объект-клон от своих получателей или вы просто принимаете разрыв в инкапсуляции?

РЕДАКТИРОВАТЬ Я понимаю, какустановить и получить методы работает, и я понимаю их преимущества.Я спрашиваю о разрыве «частного» доступа в нашей приватной переменной, когда мы возвращаем его с помощью getter по reference (если наша переменная имеет тип Number, String, int и т. Д. AS3 всегда возвращаетсязначение, а не ссылка, поэтому у нас нет проблем здесь).Возможно, не нарушена инкапсуляция, потому что мы не можем установить свойство без метода установки.Но мы можем изменить его!

См. Этот пример:

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' 

Итак, мы изменяем наш приватный var извне и без контроля, даже если у нас нет метода установки.

Ответы [ 5 ]

4 голосов
/ 17 июня 2011

Вы управляете доступом к переменной-члену, когда используете функции 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 голос
/ 17 июня 2011

Вы можете изменить приватную переменную из класса, к которому она принадлежит, но вы не можете изменить ее из-за пределов этого класса.

Наличие методов getter и setter дает вам больше возможностей (как разработчика) надthe class.

Ваше приложение будет расти, и в какой-то момент вы можете захотеть, чтобы ваш класс мог что-то делать со значением до того, как оно получит его или до того, как его установит.Вы также можете захотеть, чтобы ваш класс мог вызывать метод каждый раз, когда он устанавливает значение.Подобных вещей вы можете легко достичь, если у вас есть методы получения / установки.

Кроме того, как говорит TheDarkIn1978, если один из методов не используется, можно сделать переменную только для записи или только для чтения, которая будетогромное преимущество для инкапсуляции.

0 голосов
/ 18 июня 2011

Если вы собираетесь инкапсулировать, вам не следует предоставлять прямой доступ к сложным объектам (передается по ссылке).Вы должны посмотреть, что другие классы могут делать с вашим SomeClass.Если вам действительно нужно передать целый класс и не хотите, чтобы он был ссылочным, то добавьте метод clone.Если вы просто ожидаете, что другие классы обновят некоторые данные, принадлежащие SomeClass, предоставьте установщики для этих данных и примените их непосредственно к экземпляру SomeClass.Он требует больше кода, но достигнет цели инкапсуляции вашего класса.

0 голосов
/ 17 июня 2011

приведенный выше код аналогичен простому написанию:

public var someVar:SomeClass;

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

Кроме того, сеттеры и функции получателя позволяют вам управлять переданными параметрами, запускать события и т. Д. Например, предположим, выиметь переменную 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;
     }
  • , пожалуйста, не ругайте меня за то, что я не соответствую префиксу подчеркивания.это вопрос стиля.в то время как это "стандарт", я также думаю, что это супер некрасиво.
0 голосов
/ 17 июня 2011

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

Например, если бы у меня было:

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;
}
...