2012-10-29 23 views
5

Tôi đang trong quá trình tái cấu trúc một phần lớn mã spaghetti. Tóm lại, nó là một lớp học "Thiên Chúa" giống như các chi nhánh thành hai quá trình khác nhau tùy thuộc vào một số điều kiện. Cả hai quy trình đều dài và có nhiều mã trùng lặp.Đây có phải là một tùy chọn thiết kế tốt để gọi phương thức khởi tạo của lớp trong một nhà máy trước khi tiêm nó

Vì vậy, nỗ lực đầu tiên của tôi là trích xuất hai quy trình đó thành các lớp của riêng chúng và đặt mã chung vào một cấp độ gốc mà cả hai đều kế thừa.

Nó trông giống như sau:

public class ExportProcess 
{ 
    public ExportClass(IExportDataProvider dataProvider, IExporterFactory exporterFactory) 
    { 
     _dataProvider = dataProvider; 
     _exporterFactory = exporterFactory; 
    } 

    public void DoExport(SomeDataStructure someDataStructure) 
    { 
     _dataProvider.Load(someDataStructure.Id); 

     var exporter = _exporterFactory.Create(_dataProvider, someDataStructure); 

     exporter.Export(); 
    } 
} 

Tôi là một độc giả cuồng nhiệt của blog của Mark SEEMANN và trong this entry ông giải thích rằng mã này có một khớp nối mùi thời gian kể từ khi nó là cần thiết để gọi phương thức tải về nhà cung cấp dữ liệu trước khi nó ở trạng thái có thể sử dụng.

Trên cơ sở đó, và kể từ khi đối tượng đang được tiêm cho những người được trả về bởi các nhà máy dù sao, tôi đang nghĩ đến việc thay đổi nhà máy để làm điều này:

public IExporter Create(IExportDataProvider dataProvider, SomeDataStructure someDataStructure) 
{ 
    dataProvider.Load(someDataStructure.Id); 

    if(dataProvider.IsNewExport) 
    { 
     return new NewExportExporter(dataProvider, someDataStructure); 
    } 
    return new UpdateExportExporter(dataProvider, someDataStructure); 
} 

Bởi vì tên "DataProvider" bạn có thể đoán rằng phương thức Load thực sự đang thực hiện truy cập cơ sở dữ liệu.

Điều gì đó cho tôi biết một đối tượng đang thực hiện truy cập cơ sở dữ liệu bên trong phương thức tạo của nhà máy trừu tượng không phải là thiết kế tốt.

Có bất kỳ nguyên tắc, phương pháp hay nhất hoặc điều gì đó cho biết đây có phải là một ý tưởng tồi không?

Cảm ơn sự giúp đỡ của bạn.

+0

Rõ ràng dataProvider.Load có một số loại tác dụng phụ, dọc theo dòng lấy một thể hiện của một cái gì đó vào một tài sản? Phần còn lại của phương thức nhà máy có thực sự sử dụng 'dataProvider' và' someDataStructure' không? Nếu không, thì các đối số của bạn đối với phương thức factory-factory nên được tái cấu trúc thành chấp nhận các đối số mà nó thực sự cần. – PatrikAkerstrand

+0

@PatrikAkerstrand: Điểm tốt Patrik. Các đối tượng được tạo ra bởi nhà máy làm, trên thực tế, sử dụng các nhà cung cấp dữ liệu rất nhiều kể từ khi phương pháp tải của nó cư một số tài sản khá cần thiết. Đây là một nỗ lực tái cấu trúc đầu tiên nhưng, thật không may, đây là một khoản nợ kỹ thuật có thể không được trả trong thời gian ngắn hơn. –

+0

ok, hãy xem xét điều này sau đó: Nếu dataProvider.Load sẽ được gọi nhiều lần, điều đó có tạo ra bất kỳ vấn đề nào không? ** Nếu không **: Cool, tôi sẽ di chuyển lệnh 'Load' vào phương thức factory vì nó sẽ đơn giản hóa các máy khách (tất cả các lệnh gọi tới .Load sẽ nằm trong phương thức factory). ** Nếu có **: Bạn không có lựa chọn nào khác ngoài việc giữ nó bên ngoài nhà máy, vì bạn không biết liệu nó có được khởi tạo hay không – PatrikAkerstrand

Trả lời

2

Thông thường, một nhà máy được sử dụng để giải quyết các loại bê tông của giao diện được yêu cầu hoặc loại tóm tắt, vì vậy bạn có thể tách riêng người tiêu dùng khỏi triển khai. Vì vậy, thường là một nhà máy chỉ là sẽ khám phá hoặc xác định loại cụ thể, giúp giải quyết phụ thuộc, và nhanh chóng loại bê tông và trả lại nó. Tuy nhiên, không có quy tắc cứng hoặc nhanh về những gì nó có thể hoặc không thể làm, nhưng nó là hợp lý để cung cấp cho nó đủ quyền truy cập vào các tài nguyên mà nó cần phải giải quyết và khởi tạo các loại cụ thể.

Một cách sử dụng tốt khác của nhà máy là che giấu người tiêu dùng các loại phụ thuộc không liên quan đến người tiêu dùng. Ví dụ: có vẻ như IExportDataProvider chỉ liên quan đến nội bộ và có thể được trừu tượng hóa khỏi người tiêu dùng (chẳng hạn như ExportProcess).

Mùi mã trong ví dụ của bạn, tuy nhiên, cách sử dụng IExportDataProvider. Cách nó hiện có vẻ hoạt động, bạn sẽ có được một ví dụ của nó một lần, nhưng nó có thể thay đổi trạng thái của nó trong các tập quán tiếp theo (bằng cách gọi Load). Điều này có thể dẫn đến các vấn đề với trạng thái đồng thời và bị hỏng. Vì tôi không biết loại đó thực sự là gì hoặc nó được sử dụng như thế nào bởi IExporter của bạn, thật khó để đưa ra đề xuất. Trong ví dụ dưới đây, tôi thực hiện điều chỉnh để chúng tôi có thể giả định rằng nhà cung cấp là không quốc tịch và thay vào đó, Load trả về một số loại đối tượng trạng thái mà nhà máy có thể sử dụng để giải quyết loại xuất bản cụ thể và sau đó cung cấp dữ liệu cho nhà xuất bản. Bạn có thể điều chỉnh như bạn thấy phù hợp. Mặt khác, nếu nhà cung cấp phải là nhà nước, bạn sẽ muốn tạo một IExportDataProviderFactory, sử dụng nó trong nhà máy xuất khẩu của bạn và tạo một trường hợp mới của nhà cung cấp từ nhà máy cho mỗi cuộc gọi đến nhà máy xuất khẩu Create.

public interface IExporterFactory 
{ 
    IExporter Create(SomeDataStructure someData); 
} 

public class MyConcreteExporterFactory : IExporterFactory 
{ 
    public MyConcreteExporterFactory(IExportDataProvider provider) 
    { 
      if (provider == null) throw new ArgumentNullException(); 

      Provider = provider; 
    } 

    public IExportDataProvider Provider { get; private set; }  

    public IExporter Create(SomeDataStructure someData) 
    { 
     var providerData = Provider.Load(someData.Id); 

     // do whatever. for example... 
     return providerData.IsNewExport ? new NewExportExporter(providerData, someData) : new UpdateExportExporter(providerData, someData); 
    } 
} 

Và sau đó tiêu thụ:

public class ExportProcess 
{ 
    public ExportProcess(IExporterFactory exporterFactory) 
    { 
     if (exporterFactory == null) throw new ArgumentNullException(); 

     _exporterFactory = factory; 
    } 

    private IExporterFactory _exporterFactory; 

    public void DoExport(SomeDataStructure someData) 
    { 
     var exporter = _exporterFactory.Create(someData); 
     // etc. 
    } 
} 
+0

Có một vấn đề với ví dụ của bạn. Nhà cung cấp tải một vài thuộc tính của các loại khác nhau với các dữ liệu khác nhau. Nếu tôi tách tất cả các cuộc gọi đó sao cho mỗi phương thức trả về dữ liệu mà nó được truy vấn thì hàm tạo Exporter Concrete sẽ có một vài tham số. Tôi biết đây là một dấu hiệu cho thấy lớp học vẫn đang làm quá nhiều. Với những suy nghĩ này trong tâm trí, bạn vẫn coi đây là lựa chọn tốt nhất? –

+1

@SergioRomero Trong trường hợp đó, bạn có thể xem xét một bộ điều hợp. Hãy để nhà máy được sử dụng để giải quyết các loại IExporter bạn cần, và sử dụng một adapter để thực sự môi giới tạo ra IExporter. Tôi sẽ xem liệu tôi có thể cập nhật câu trả lời của mình bằng một ví dụ về ý tôi không. – HackedByChinese