Tôi thường có cảm giác xấu về mã có mô hình xem trực tiếp giao tiếp với người khác. Tôi thích ý tưởng rằng phần VVM của mẫu nên về cơ bản có thể cắm được và không có gì bên trong khu vực mã đó phụ thuộc vào sự tồn tại của bất kỳ thứ gì khác trong phần đó. Lý do đằng sau điều này là không tập trung vào logic, nó có thể trở nên khó khăn để xác định trách nhiệm. Mặt khác, dựa trên mã thực tế của bạn, nó có thể chỉ là ApplicationViewModel được đặt tên không đúng, nó không làm cho một mô hình có thể truy cập được, vì vậy đây có thể chỉ là một sự lựa chọn nghèo nàn về tên.
Dù bằng cách nào đi nữa, giải pháp đó sẽ làm hỏng trách nhiệm. Con đường tôi nhìn thấy nó, bạn có ba điều cần đạt được:
- Cho phép người sử dụng để yêu cầu để kết nối đến một địa chỉ
- Sử dụng địa chỉ đó để kết nối với một máy chủ
- Persist địa chỉ đó.
Tôi muốn đề nghị bạn cần ba lớp thay vì hai lớp của bạn.
public class ServiceProvider
{
public void Connect(Uri address)
{
//connect to the server
}
}
public class SettingsProvider
{
public void SaveAddress(Uri address)
{
//Persist address
}
public Uri LoadAddress()
{
//Get address from storage
}
}
public class ConnectionViewModel
{
private ServiceProvider serviceProvider;
public ConnectionViewModel(ServiceProvider provider)
{
this.serviceProvider = serviceProvider;
}
public void ExecuteConnectCommand()
{
serviceProvider.Connect(Address);
}
}
Điều tiếp theo để quyết định là cách địa chỉ đến Trình cài đặt chuyên biệt. Bạn có thể vượt qua nó từ ConnectionViewModel như bạn hiện tại, nhưng tôi không quan tâm đến điều đó bởi vì nó làm tăng sự ghép nối của mô hình khung nhìn và nó không phải là trách nhiệm của ViewModel để biết rằng nó cần sự bền bỉ. Một lựa chọn khác là thực hiện cuộc gọi từ ServiceProvider, nhưng nó không thực sự cảm thấy với tôi như nó phải là trách nhiệm của ServiceProvider. Trong thực tế nó không cảm thấy như trách nhiệm của bất cứ ai khác hơn là SettingsProvider. Điều này khiến tôi tin rằng nhà cung cấp thiết lập nên lắng nghe những thay đổi đối với địa chỉ được kết nối và tiếp tục tồn tại mà không có sự can thiệp.Nói cách khác một sự kiện:
public class ServiceProvider
{
public event EventHandler<ConnectedEventArgs> Connected;
public void Connect(Uri address)
{
//connect to the server
if (Connected != null)
{
Connected(this, new ConnectedEventArgs(address));
}
}
}
public class SettingsProvider
{
public SettingsProvider(ServiceProvider serviceProvider)
{
serviceProvider.Connected += serviceProvider_Connected;
}
protected virtual void serviceProvider_Connected(object sender, ConnectedEventArgs e)
{
SaveAddress(e.Address);
}
public void SaveAddress(Uri address)
{
//Persist address
}
public Uri LoadAddress()
{
//Get address from storage
}
}
này giới thiệu khớp nối chặt chẽ giữa ServiceProvider và SettingsProvider, mà bạn muốn tránh nếu có thể và tôi muốn sử dụng một EventAggregator đây, mà tôi đã thảo luận trong một câu trả lời cho this question
Để giải quyết các vấn đề về khả năng kiểm tra, bây giờ bạn có một kỳ vọng rất được xác định cho những gì mỗi phương pháp sẽ làm. ConnectionViewModel sẽ gọi kết nối, ServiceProvider sẽ kết nối và SettingsProvider sẽ tiếp tục tồn tại. Để kiểm tra ConnectionViewModel có thể bạn muốn chuyển đổi các khớp nối với ServiceProvider từ một lớp học để một giao diện:
public class ServiceProvider : IServiceProvider
{
...
}
public class ConnectionViewModel
{
private IServiceProvider serviceProvider;
public ConnectionViewModel(IServiceProvider provider)
{
this.serviceProvider = serviceProvider;
}
...
}
Sau đó, bạn có thể sử dụng một khuôn khổ mocking để giới thiệu một IServiceProvider chế giễu rằng bạn có thể kiểm tra để đảm bảo rằng các phương pháp kết nối được gọi với các tham số dự kiến.
Kiểm tra hai lớp khác là khó khăn hơn vì chúng sẽ dựa vào việc có một máy chủ thực và thiết bị lưu trữ liên tục thực sự. Bạn có thể thêm nhiều lớp khác nhau để trì hoãn điều này (ví dụ như PersistenceProvider mà Trình cài đặt sử dụng) nhưng cuối cùng bạn rời khỏi thế giới kiểm tra đơn vị và nhập thử nghiệm tích hợp. Nói chung khi tôi viết mã với các mẫu bên trên các mô hình và các mô hình xem có thể có được phạm vi kiểm tra đơn vị tốt, nhưng các nhà cung cấp yêu cầu các phương pháp thử nghiệm phức tạp hơn. Tất nhiên, một khi bạn đang sử dụng EventAggregator để ngắt kết nối và IOC để tạo điều kiện thử nghiệm nó có lẽ đáng xem xét một trong các khuôn khổ tiêm phụ thuộc như Prism của Microsoft, nhưng ngay cả khi bạn quá muộn trong quá trình phát triển để trở lại -Hệ thống kiến trúc rất nhiều các quy tắc và các mẫu có thể được áp dụng cho mã hiện tại theo một cách đơn giản hơn.
Tôi đã thực sự rót mã Onyx trong vài ngày qua để thu thập một số thông tin chi tiết về WPF. Nó chắc chắn đã đặt ra rất nhiều suy nghĩ của tôi và tôi đã học được một chút. –
Cảm ơn. Ngay cả khi bạn không sử dụng Onyx, tôi hy vọng những ý tưởng này rất hữu ích. Onyx là chắc chắn không cần thiết ở đây, mặc dù các giải pháp giao diện dịch vụ tôi nghĩ rằng thực sự là những gì bạn đang tìm kiếm. – wekempf