2013-08-15 30 views
5

Trong Matlab, tôi có thể xác định một lớp học như vậy:động gán các getter cho một tài sản phụ thuộc trong MATLAB

classdef klass < handle 
    properties(Dependent) 
     prop 
    end 
end 

Matlab là hoàn toàn hạnh phúc instantiating một đối tượng của lớp này, thậm chí không xác định một getter cho prop. Nó chỉ thất bại khi tôi cố gắng truy cập nó (dễ hiểu). Tôi muốn đặt GetMethod động dựa trên tên của tài sản.

Thật không may, ngay cả khi thuộc tính là phụ thuộc, trường meta.property cho GetMethod vẫn chỉ đọc. Và trong khi kế thừa từ dynamicprops có thể cho phép thêm một thuộc tính và đặt chương trình GetMethod của nó theo chương trình trong mọi trường hợp, tôi không tin rằng nó có thể được sử dụng để thay đổi thuộc tính hiện tại. Tôi có thể phải đi tuyến đường này, nhưng như propphải tồn tại cho mỗi đối tượng tôi muốn chỉ đơn giản là đặt getter trên cơ sở từng lớp. Là một điều như vậy có thể?

Một giải pháp thay thế có thể là thông qua một số phương pháp nắm bắt tất cả. Trong các ngôn ngữ khác, điều này có thể được thực hiện thông qua một giống như Ruby method_missing hoặc giống như __get() giống như PHP. Nhưng theo như tôi biết không có (tài liệu hoặc bằng cách khác) tương tự trong Matlab.


(trường hợp sử dụng của tôi: lớp này được thừa hưởng bởi nhiều lớp con người dùng định nghĩa, và tất cả các thuộc tính phụ thuộc của họ được truy cập một cách tương tự, chỉ thay đổi dựa trên các tên thuộc tính Thay vì yêu cầu người dùng viết get.*. các phương thức gói một cuộc gọi đến mã chung cho mỗi và mọi thuộc tính phụ thuộc của chúng, tôi muốn đặt tất cả chúng một cách động với các con trỏ hàm ẩn danh có chứa siêu dữ liệu cần thiết).

Trả lời

4

Đây là đề nghị của tôi: tạo ra một phương pháp trong các lớp cha gọi add_dyn_prop. Phương thức này được gọi trong các lớp con thay vì tạo một cách dependent property theo cách thông thường.

Ý tưởng là lớp cha kế thừa từ dynamicprops và sử dụng addprop đến add thuộc tính mới và đặt phương thức truy cập theo cách thủ công dựa trên tên của nó.

classdef klass < dynamicprops 
    methods (Access = protected) 
     function add_dyn_prop(obj, prop, init_val, isReadOnly) 
      % input arguments 
      narginchk(2,4); 
      if nargin < 3, init_val = []; end 
      if nargin < 4, isReadOnly = true; end 

      % create dynamic property 
      p = addprop(obj, prop); 

      % set initial value if present 
      obj.(prop) = init_val; 

      % define property accessor methods 
      % NOTE: this has to be a simple function_handle (@fun), not 
      % an anonymous function (@()..) to avoid infinite recursion 
      p.GetMethod = @get_method; 
      p.SetMethod = @set_method; 

      % nested getter/setter functions with closure 
      function set_method(obj, val) 
       if isReadOnly 
        ME = MException('MATLAB:class:SetProhibited', sprintf(... 
         'You cannot set the read-only property ''%s'' of %s', ... 
         prop, class(obj))); 
        throwAsCaller(ME); 
       end 
       obj.(prop) = val; 
      end 
      function val = get_method(obj) 
       val = obj.(prop); 
      end 
     end 
    end 
end 

bây giờ trong lớp con, thay vì xác định một tài sản phụ thuộc theo cách thông thường, chúng tôi sử dụng chức năng này được thừa hưởng mới trong các nhà xây dựng để xác định một tài sản năng động:

classdef subklass < klass 
    %properties (Dependent, SetAccess = private) 
    % name 
    %end 
    %methods 
    % function val = get.name(obj) 
    %  val = 'Amro'; 
    % end 
    %end 

    methods 
     function obj = subklass() 
      % call superclass constructor 
      obj = [email protected](); 

      % define new properties 
      add_dyn_prop(obj, 'name', 'Amro'); 
      add_dyn_prop(obj, 'age', [], false) 
     end    
    end 
end 

Sản lượng:

>> o = subklass 
o = 
    subklass with properties: 

    age: [] 
    name: 'Amro' 
>> o.age = 10 
o = 
    subklass with properties: 

    age: 10 
    name: 'Amro' 
>> o.name = 'xxx' 
You cannot set the read-only property 'name' of subklass. 

Tất nhiên bây giờ bạn có thể tùy chỉnh phương thức getter dựa trên tên thuộc tính như bạn dự định ban đầu.


EDIT:

Căn cứ ý kiến, xin vui lòng tìm thấy bên dưới một biến thể nhẹ của kỹ thuật tương tự đã thảo luận ở trên.

Ý tưởng là yêu cầu phân lớp để tạo thuộc tính (được định nghĩa là trừu tượng trong siêu lớp) chứa tên của các thuộc tính động mong muốn được tạo. Hàm khởi tạo của lớp cha sau đó sẽ tạo các thuộc tính động được chỉ định, thiết lập các phương thức truy cập của chúng thành các hàm chung (có thể tùy chỉnh hành vi của chúng dựa trên tên thuộc tính như bạn đã yêu cầu). Tôi đang sử dụng lại cùng chức năng add_dyn_prop tôi đã đề cập trước đây.

Trong phân lớp, chúng tôi chỉ cần thực hiện thuộc tính trừu tượng dynamic_props được thừa kế, được khởi tạo với danh sách tên (hoặc {} nếu bạn không muốn tạo bất kỳ thuộc tính động nào). Ví dụ chúng ta viết:

classdef subklass < klass 
    properties (Access = protected) 
     dynamic_props = {'name', 'age'} 
    end 

    methods 
     function obj = subklass() 
      obj = [email protected](); 
     end 
    end 
end 

Các lớp cha cũng tương tự như những gì chúng tôi đã có trước khi trước đó, chỉ là bây giờ nó trách nhiệm của mình để gọi add_dyn_prop trong constructor của nó cho mỗi tên thuộc tính:

classdef klass < dynamicprops  % ConstructOnLoad 
    properties (Abstract, Access = protected) 
     dynamic_props 
    end 
    methods 
     function obj = klass() 
      assert(iscellstr(obj.dynamic_props), ... 
       '"dynamic_props" must be a cell array of strings.'); 
      for i=1:numel(obj.dynamic_props) 
       obj.add_dyn_prop(obj.dynamic_props{i}, [], false); 
      end 
     end 
    end 

    methods (Access = private) 
     function add_dyn_prop(obj, prop, init_val, isReadOnly) 
      % input arguments 
      narginchk(2,4); 
      if nargin < 3, init_val = []; end 
      if nargin < 4, isReadOnly = true; end 

      % create dynamic property 
      p = addprop(obj, prop); 
      %p.Transient = true; 

      % set initial value if present 
      obj.(prop) = init_val; 

      % define property accessor methods 
      p.GetMethod = @get_method; 
      p.SetMethod = @set_method; 

      % nested getter/setter functions with closure 
      function set_method(obj,val) 
       if isReadOnly 
        ME = MException('MATLAB:class:SetProhibited', sprintf(... 
         'You cannot set the read-only property ''%s'' of %s', ... 
         prop, class(obj))); 
        throwAsCaller(ME); 
       end 
       obj.(prop) = val; 
      end 
      function val = get_method(obj) 
       val = obj.(prop); 
      end 
     end 
    end 
end 

Lưu ý: Tôi không sử dụng thuộc tính lớp ConstructOnLoad hoặc thuộc tính bất động sản Transient, vì tôi vẫn không chắc chắn cách chúng ảnh hưởng đến việc tải đối tượng từ tệp MAT đã lưu liên quan đến thuộc tính động.

>> o = subklass 
o = 
    subklass with properties: 

    age: [] 
    name: [] 

>> o.name = 'Amro'; o.age = 99 
o = 
    subklass with properties: 

    age: 99 
    name: 'Amro' 
+1

Điều này gần nhất với những gì tôi đã kết thúc: Tôi có mỗi phân lớp xác định thuộc tính 'dynamic_props' và lớp cha (buộc phải' [ConstructOnLoad] (http://www.mathworks.com/help/matlab/matlab_oop/class -constructor-methods.html) ') khởi tạo tất cả chúng trong constructor của nó, thiết lập GetMethod thành một hàm ẩn danh chứa tên thuộc tính để cho phép thực thi chung. Một chút đơn giản hơn và được xác định rõ hơn cho người dùng, tôi nghĩ vậy. Tôi chỉ muốn Matlab có khả năng lập trình OO năng động hơn. Chúc mừng! –

+1

@MattB .: Tôi đã đăng một triển khai thay thế dựa trên những gì bạn mô tả. – Amro

+0

Yup, chính xác như thế nào tôi đã làm nó, ngoại trừ với Transient = true và constructOnLoad. Dường như nó hoạt động tốt với việc lưu và tải cho các mục đích của tôi. Tôi đã xem xét trả lời câu hỏi của riêng tôi, nhưng đã tìm ra câu hỏi của bạn là đủ gần. Bây giờ nó thực sự là! –

2

Kiểm tra xem đây có phải là điều bạn muốn không. Vấn đề là người dùng sẽ cần phải có được các thuộc tính bằng cách sử dụng(), có thể khá nhàm chán, nhưng dù sao, tôi nghĩ theo cách này bạn có thể thay đổi các biến. Bạn không thể thay đổi chúng trực tiếp trên lớp, nhưng bạn có thể thay đổi các giá trị thuộc tính của đối tượng theo yêu cầu. Nó không cần phải thay đổi các giá trị trên hàm tạo, bạn có thể làm điều đó bằng cách sử dụng một hàm khác sẽ được thừa hưởng bởi các lớp.

klass1.m

classdef(InferiorClasses = {?klass2}) klass < handle 

    methods 
    function self = klass 
     selfMeta = metaclass(self); 
     names = {selfMeta.PropertyList.Name}; 
     for name = names 
     switch name{1} 
     case 'prop_child_1' 
      self.(name{1}) = @newGetChild1PropFcn; 
     case 'prop_child_2' 
      self.(name{1}) = @newGetChild2PropFcn; 
     end 
     end 
    end 
    end 
    methods(Static) 
    function out = prop 
     out = @defaultGetPropFcn; 
    end 
    end 
end 

function out = defaultGetPropFcn 
    out = 'defaultGetPropFcn'; 
end 

function out = newGetChild1PropFcn 
    out = 'newGetChild1PropFcn'; 
end 

function out = newGetChild2PropFcn 
    out = 'newGetChild2PropFcn'; 
end 

klass2.m

classdef klass2 < klass 
    properties 
    prop_child_1 = @defaultGetChildPropFcn1 
    prop_child_2 = @defaultGetChildPropFcn2 
    end 
    methods 
    function self = klass2 
     self = [email protected]; 
    end 
    end 
end 

function out = defaultGetChildPropFcn1 
    out = 'defaultGetChildPropFcn1'; 
end 
function out = defaultGetChildPropFcn2 
    out = 'defaultGetChildPropFcn2'; 
end 

Output:

a = klass2 
b=a.prop_child_1() 


b = 

newGetChild1PropFcn 
+0

Vâng, điều đó tương tự như những gì tôi đề cập trong đoạn cuối cùng (trường hợp sử dụng) của tôi. Điều đó làm việc tốt cho một thuộc tính, nhưng đó là rất nhiều bản mẫu cho mỗi thuộc tính trong mỗi lớp con. –

+0

@Matt B. Bạn không thể viết một phương thức trừu tượng được xác định cho mỗi phân lớp mà thay đổi tất cả các thuộc tính phụ thuộc vào fcnHandle được xác định? – Werner

+0

@Matt B. Hay chính xác là bạn đang cố gắng tránh làm? – Werner

Các vấn đề liên quan