2015-06-06 22 views
5

Tôi có một lớp con Bicycle thừa kế từ Agent. Các đại lý có một tài sản mà phụ thuộc vào xe đạp để xác định nó. Cụ thể, mô hình vật lý cho tác nhân cần được khởi tạo với các ràng buộc vận tốc và tăng tốc được xác định trên cơ sở từng xe đạp và sẽ khác với một loại tác nhân khác.Bắt buộc một lớp con để khởi tạo thuộc tính cha mẹ sau khi tính toán

Vấn đề tôi có là tôi không thể chuyển các tham số cần tính toán (vận tốc/gia tốc yêu cầu tính toán để vẽ chúng từ phân phối lý thuyết) cho điều này trong constructor base() vì tất nhiên lớp con chưa được khởi tạo.

Tính toán được thực hiện một lần cho mỗi trường hợp xe đạp nhưng được sử dụng nhiều lần để một phương pháp tĩnh đơn giản sẽ không thực hiện công việc. Tôi chỉ có thể gọi một phương pháp protected trong phụ huynh sau khi chúng được tính toán nhưng AFAIK không có cách nào để thực thi điều này ở trẻ em, hoặc đặc biệt hơn trong bất kỳ trẻ em nào trong tương lai mà tôi có thể không viết.

Vì vậy, ví dụ, tôi có thể:

public abstract class Agent 
{ 
    protected IPhysics PluginPhysics { get; set; } 

    protected Agent(...) 
    { 
    } 
} 

public class Bicycle : Agent 
{ 
    private double maxA; 

    public Bicycle(Object anotherParameter) : base(...) 
    { 
     maxA = ComputationOfMaxA(); 
     this.PluginPhysics = new Physics(anotherParameter, maxA); 
    } 

    private static double ComputationOfMaxA() 
    { 
     ... 
    } 
    ... 
} 

hoặc tôi có thể:

public abstract class Agent 
{ 
    protected IPhysics PluginPhysics { get; private set; } 

    protected Agent(...) 
    { 
    } 

    protected void SetupPhysics(Physics physics) 
    { 
     this.PluginPhysics = physics; 
    } 
} 

public class Bicycle : Agent 
{ 
    private double maxA; 

    public Bicycle(Object anotherParameter) : base(...) 
    { 
     maxA = ComputationOfMaxA(); 
     SetupPhysics(new Physics(anotherParameter,maxA)); 
    } 

    private static double ComputationOfMaxA() 
    { 
     ... 
    } 

    ... 
} 

Tôi không muốn làm một trong những người như không có cách nào thời gian biên dịch để đảm bảo rằng đứa trẻ initialises PluginPhysics mà tôi có thể nghĩ đến, và tôi muốn PluginPhysics không thể thay đổi khi nó được khởi tạo. Tôi cũng không muốn có các phần của tham số cần phải đi vào Physics bên ngoài lớp Bicycle. Tôi đánh giá cao rằng tất cả những điều này có thể không đồng thời có thể.

Vì vậy, ngắn gọn tài liệu được viết mạnh hoặc một loạt kiểm tra null thời gian chạy trong lớp cha trước khi bất kỳ đối tượng lớp nào được gọi, có cách rõ ràng C# -ish cách tôi thiếu buộc một đứa trẻ để khởi tạo một trường lớp cha mẹ trước khi sử dụng nếu bạn không thể làm điều đó trong constructor?

+2

Tôi đã chỉnh sửa mã của bạn một lần chạm để làm cho nó rõ ràng hơn, bạn dựa vào ComputationOfMaxA để hoàn thành trước khi bạn tạo đối tượng vật lý. –

Trả lời

3

d4Rk's answer là rất gần, tuy nhiên bạn nên cố gắng không gọi các phương thức ảo từ một constructor như bad things can happen. Tuy nhiên, nếu bạn sử dụng kết hợp các thủ thuật tải Lazy và ISupportInitialize bạn có thể trì hoãn việc tạo plugin cho đến sau khi hàm tạo được hoàn tất.

public abstract class Agent : ISupportInitialize 
{ 
    private bool _initialized = false; 

    private IPhysics _pluginPhysics; 
    protected IPhysics PluginPhysics 
    { 
     get 
     { 
      if(!_initialized) 
       EndInit(); 
      return _pluginPhysics; 
     } 
    } 

    protected Agent(...) 
    { 
    } 

    protected abstract IPhysics CreatePhysics(); 

    ISupportInitialize.BeginInit() 
    { 
     //We make this a explicit implementation because it will not 
     //do anything so we don't need to expose it. 
    } 

    public void EndInit() 
    { 
     if(_initialized) 
      return; 

     _initialized = true; 
     _pluginPhysics = CreatePhysics(); 
    } 
} 

public class Bicycle : Agent 
{ 
    private double maxA; 
    Object _anotherParameter; 

    public Bicycle(Object anotherParameter) 
    { 
     _anotherParameter = anotherParameter; 
    } 
    protected override IPhysics CreatePhysics() 
    { 
     ComputationOfMaxA(); 
     return new Physics(anotherParameter, maxA); 
    } 
} 

Người dùng của lớp học của bạn sẽ cần phải gọi EndInit() sau khi họ nhận được một đối tượng trở lại làm cho đối tượng IPhysics được tạo ra, tuy nhiên nếu họ quên để gọi hàm khởi tạo các getter trên đối tượng vật lý sẽ kích hoạt tự khởi chạy cuộc gọi lần đầu tiên nó được sử dụng.

Bạn có thể làm mọi thứ tôi đã hiển thị mà không cần giao diện ISupportInitialize và chỉ có phương thức công khai Initalize() trên lớp cơ sở nhưng tôi muốn hiển thị giao diện khung khi chúng phù hợp.

+0

Điều này là thanh lịch hơn so với các loại kiểm tra null tôi đã nghĩ đến vì nó sử dụng một giao diện thích hợp mà là một cách rõ ràng để khởi tạo "đồng thuộc tính phụ thuộc" mà về cơ bản là những gì tôi có ở đây. Nó chắc chắn cảm thấy nhiều nhất 'C# ish'. Cảm ơn. – Smalltown2k

2

Điều gì về việc thực thi lớp con để thực hiện phương thức CreatePhysics và gọi điều này trong trình quản lý cơ sở?

Như thế này:

public abstract class Agent 
{ 
    protected IPhysics PluginPhysics { get; private set; } 

    protected Agent(...) 
    { 
     var physics = CreatePhysics(); 
     SetupPhysics(physics); 
    } 

    void SetupPhysics(IPhysics physics) 
    { 
     this.PluginPhysics = physics; 
    } 

    protected abstract IPhysics CreatePhysics(); 
} 

public class Bicycle : Agent 
{ 
    private double maxA; 

    protected override IPhysics CreatePhysics() 
    { 
     ComputationOfMaxA(); 
     return new Physics(maxA); 
    } 
} 
+0

Điều này là tuyệt vời miễn là plugin Vật lý cũng không cần những thứ đi vào thông qua các nhà xây dựng xe đạp ... mà tiếc là trường hợp của tôi. Tôi có thể cập nhật câu hỏi này. – Smalltown2k

+0

Nói chung nó được cau mày khi gọi một lớp trừu tượng/ảo trong hàm tạo. Điều này là do các nhà xây dựng con sẽ không bắt đầu chạy và các biến cấp lớp sẽ không được đưa vào, khi bạn có nhiều cấp độ thừa kế, điều này có thể khá khó khăn để quản lý. –

+0

Tuy nhiên, nếu bạn kết hợp phương thức này với ['ISupportInitialize'] (https://msdn.microsoft.com/en-us/library/system.componentmodel.isupportinitialize%28v=vs.110%29.aspx) thì bạn có 'EndInit()' gọi 'CreatePhysics()' mọi thứ sẽ ổn. –

2

Làm thế nào về việc các nhà xây dựng cho Agent lấy đối tượng IPhysics và làm cho nó protected Sau đó, trong lớp Bicycle, bạn buộc phải gọi constructor trên cơ sở đó thiết lập lớp học của bạn bất động sản:

public class Agent 
{ 
    protected IPhysics PluginPhysics { get; private set; } 

    protected Agent(IPhysics physicsPlugin) 
    { 
     PluginPhysics = physicsPlugin; 
    } 
} 

public class Bicycle : Agent 
{ 
    public Bicycle(IPhysics physicsPlugin) 
     : base(physicsPlugin) 
    { 
     Console.WriteLine("Bicycle ctor"); 
    } 
} 
+0

Và bạn thực hiện các phép tính cho 'physicsPlugin' ở đâu? – d4Rk

+0

Tôi có thể sẽ đến đây. Những gì tôi đang cố gắng để tránh là những thứ nhất định cần phải đi vào constructor vật lý đó từ bên ngoài lớp xe đạp. Mặc dù tôi đánh giá cao đó không phải là trong câu hỏi, mà tôi đã cập nhật. – Smalltown2k

+0

Nếu bạn không muốn những phần đó bên ngoài lớp Xe đạp, vậy tại sao không giữ mọi thứ bên trong 'Tác nhân'? Tôi đoán tôi là một chút bối rối như những gì chính xác bạn đang cố gắng đạt được ở đây. – DavidG

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