Lớp với các thành viên có thể thay đổi trong quá trình tạo nhưng sau đó không thay đổi


22

Tôi có một thuật toán tạo ra một bộ sưu tập các đối tượng. Các đối tượng này có thể thay đổi trong quá trình tạo, vì chúng bắt đầu với rất ít, nhưng sau đó chúng được điền dữ liệu ở các vị trí khác nhau trong thuật toán.

Sau khi thuật toán hoàn thành, các đối tượng sẽ không bao giờ bị thay đổi - tuy nhiên chúng được tiêu thụ bởi các phần khác của phần mềm.

Trong các kịch bản này, nó có được coi là thực hành tốt để có hai phiên bản của lớp, như được mô tả dưới đây không?

  • Cái có thể thay đổi được tạo bởi thuật toán, sau đó
  • Khi hoàn thành thuật toán, dữ liệu được sao chép vào các đối tượng bất biến được trả về.

3
Bạn có thể chỉnh sửa câu hỏi của bạn để làm rõ vấn đề / câu hỏi của bạn là gì?
Simon Bergot

Câu trả lời:


46

Bạn có thể có thể sử dụng mô hình xây dựng . Nó sử dụng một đối tượng 'người xây dựng' riêng biệt với mục đích thu thập dữ liệu cần thiết và khi tất cả dữ liệu được thu thập, nó sẽ tạo ra đối tượng thực tế. Các đối tượng được tạo ra có thể là bất biến.


Giải pháp của bạn là giải pháp chính xác cho các yêu cầu của tôi (không phải tất cả trong số đó đã được nêu). Khi điều tra, các đối tượng trả lại không có đặc điểm giống nhau. Lớp trình xây dựng có rất nhiều trường rỗng và khi dữ liệu được xây dựng, nó chọn một trong 3 lớp khác nhau để tạo: các trường này có liên quan với nhau theo kế thừa.
Paul Richards

2
@Paul Trong trường hợp đó, nếu câu trả lời này giải quyết được vấn đề của bạn, bạn nên đánh dấu nó là chấp nhận.
Đi xe đạp

24

Một cách đơn giản để đạt được điều này là có một giao diện cho phép một người đọc các thuộc tính và chỉ gọi các phương thức chỉ đọc và một lớp thực hiện giao diện đó cũng cho phép bạn viết lớp đó.

Phương thức của bạn tạo ra nó, giao dịch với cái trước và sau đó trả về cái sau chỉ cung cấp giao diện chỉ đọc để tương tác. Điều này sẽ không yêu cầu sao chép và nó cho phép bạn dễ dàng tinh chỉnh các hành vi bạn muốn có sẵn cho người gọi trái ngược với người tạo.

Lấy ví dụ này:

public interface IPerson 
{
    public String FirstName 
    {
        get;
    }

    public String LastName 
    {
        get;
    }
} 

public class PersonImpl : IPerson 
{
    private String firstName, lastName;

    public String FirstName 
    {
        get { return firstName; }
        set { firstName = value; }
    }

    public String LastName 
    {
        get { return lastName; }
        set { lastName = value; }
    }
}

class Factory 
{
    public IPerson MakePerson() 
    {
        PersonImpl person = new PersonImpl();
        person.FirstName = 'Joe';
        person.LastName = 'Schmoe';
        return person;
    }
}

Nhược điểm duy nhất của phương pháp này là người ta có thể đơn giản chuyển nó đến lớp thực hiện. Nếu đó là vấn đề bảo mật, thì chỉ cần sử dụng phương pháp này là không đủ. Một cách giải quyết cho vấn đề này là bạn có thể tạo một lớp mặt tiền để bọc lớp có thể thay đổi, chỉ đơn giản là trình bày một giao diện mà người gọi làm việc cùng và không thể có quyền truy cập vào đối tượng bên trong.

Bằng cách này, thậm chí không đúc sẽ giúp bạn. Cả hai đều có thể xuất phát từ cùng một giao diện chỉ đọc, nhưng việc truyền đối tượng được trả về sẽ chỉ cung cấp cho bạn lớp Facade, điều này là bất biến vì nó không thay đổi trạng thái cơ bản của lớp có thể thay đổi được bọc.

Điều đáng nói là điều này không theo xu hướng điển hình trong đó một đối tượng bất biến được xây dựng một lần và mãi mãi thông qua nhà xây dựng của nó. Có thể hiểu được, bạn có thể phải xử lý nhiều tham số, nhưng bạn nên tự hỏi mình nếu tất cả các tham số này cần được xác định trước hoặc nếu một số có thể được giới thiệu sau. Trong trường hợp đó, nên sử dụng một hàm tạo đơn giản với các tham số cần thiết. Nói cách khác, không sử dụng mẫu này nếu nó đang che đậy một vấn đề khác trong chương trình của bạn.


1
Bảo mật không tốt hơn bằng cách trả về một đối tượng "chỉ đọc", bởi vì mã nhận được đối tượng, vẫn có thể sửa đổi đối tượng bằng cách sử dụng sự phản chiếu. Ngay cả một chuỗi có thể được sửa đổi (Không được sao chép, sửa đổi tại chỗ) bằng cách sử dụng sự phản chiếu.
MTilsted

Vấn đề bảo mật có thể được giải quyết gọn gàng với một lớp học riêng
Esben Skov Pedersen

@Esben: Bạn vẫn phải tranh luận với MS07-052: Kết quả thực thi mã trong thực thi mã . Mã của bạn đang chạy trong cùng bối cảnh bảo mật như mã của họ, vì vậy họ có thể chỉ cần đính kèm trình gỡ lỗi và làm bất cứ điều gì họ muốn.
Kevin

Kevin1 bạn có thể nói rằng về tất cả các đóng gói. Tôi không cố gắng bảo vệ chống lại sự phản chiếu.
Esben Skov Pedersen

1
Vấn đề với việc sử dụng từ "bảo mật" là ngay lập tức ai đó cho rằng những gì tôi nói là tùy chọn an toàn hơn tương đương với bảo mật tối đa và thực tiễn tốt nhất. Tôi cũng không bao giờ nói. Nếu bạn đang trao thư viện cho ai đó sử dụng, trừ khi bị xáo trộn (và đôi khi ngay cả khi bị che khuất), bạn có thể quên đi việc đảm bảo an ninh. Tuy nhiên, tôi nghĩ rằng tất cả chúng ta đều có thể đồng ý về thực tế rằng nếu bạn giả mạo một đối tượng mặt tiền được trả lại bằng cách sử dụng sự phản chiếu để truy xuất đối tượng bên trong có trong đó bạn không sử dụng chính xác thư viện như nó nên được sử dụng.
Neil

8

Bạn có thể sử dụng mẫu Builder như @JacquesB nói hoặc nghĩ khác tại sao thực sự các đối tượng này của bạn phải có thể thay đổi trong quá trình tạo?

Nói cách khác, tại sao quá trình tạo chúng phải được lan truyền kịp thời, trái ngược với việc chuyển tất cả các giá trị cần thiết vào hàm tạo và tạo các thể hiện trong một lần?

Bởi vì Builder có thể là một giải pháp tốt cho vấn đề sai.

Nếu vấn đề là bạn kết thúc với một hàm tạo có độ dài 10 tham số và bạn muốn giảm thiểu nó bằng cách xây dựng đối tượng từng chút một, thì điều đó có thể chỉ ra rằng thiết kế đã bị rối và 10 giá trị này phải là " đóng gói "/ được nhóm lại thành một vài đối tượng ... hoặc đối tượng chính tách thành một vài đối tượng nhỏ hơn ...

Trong trường hợp đó - dính vào sự bất biến tất cả các cách, chỉ cần cải thiện thiết kế.


Sẽ rất khó để tạo tất cả cùng một lúc vì mã thực hiện nhiều truy vấn cơ sở dữ liệu để lấy dữ liệu; nó so sánh dữ liệu trong các bảng khác nhau và trong các cơ sở dữ liệu khác nhau.
Paul Richards
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.