2016-09-21 15 views
5

Tôi có 1 giao diện:Factory để tạo các đối tượng khác nhau của cùng một giao diện

public interface ISummary 
{ 
    int EventId {get; set;} 
} 

Và nhiều lớp bê tông mà thực hiện giao diện này:

public class EmployeeSummary : ISummary 
{ 
    public int EventId {get; set;}, 
    public int TotalUniqueCount {get; set;} 
    public int Location {get; set;} 
} 

public class CarSummary : ISummary 
{ 
    public int EventId {get; set;} 
    public int TotalMiles {get; set;} 
    public int TotalHours {get; set;} 
} 

vv ....

duy nhất tài sản được chia sẻ là EventId. Có cách nào để có phương pháp nhà máy 1 tạo ra tất cả các đối tượng tóm tắt này không? Tôi muốn 1 điểm vào để quyết định đối tượng nào cần tạo.

Vì vậy, một cái gì đó như:

public ISummary CreateSummary(ConcreteObjectType with properties) 
{ 
if EmployeeSummary 
--Call this method to create and return EmployeeSummary 

if CarSummary 
--Call this method create and return CarSummary 
} 

Tôi muốn tất cả các cuộc gọi trong các lớp khác để gọi phương pháp này thay vì tạo ra các đối tượng bản thân.

Phần tôi đang gặp phải là làm cách nào để chuyển thuộc tính để gán cho các đối tượng cho phương thức CreateSummary này vì tất cả các thuộc tính trên các đối tượng sẽ khác nhau?

Tôi cũng đang mở để thay đổi các đối tượng tại thời điểm này nếu có mẫu thiết kế tốt hơn mà tôi nên sử dụng ở đây.

+1

bạn một phương pháp nhà máy chung với một đại biểu hành động để cư các thuộc tính bạn muốn – Nkosi

Trả lời

9

Vâng, đó là chính xác lý do tại sao Factory Method mô hình tồn tại:

public class SummaryFactory 
{   
    // new instance with values assigned by action delegate or default 
    public T Create<T>(Action<T> action = null) where T : ISummary, new() 
    { 
     var result = new T(); 

     action?.Invoke(result); 

     return result; 
    } 

    // with object to assign value from (map) 
    public T Create<T>(object map) where T : ISummary, new() 
    { 
     var result = new T(); 
     PropertyInfo[] props = map.GetType().GetProperties(); 
     PropertyInfo[] tProps = typeof(T).GetProperties(); 

     foreach (var prop in props) 
     { 
      var upperPropName = prop.Name.ToUpper(); 
      var foundProperty = tProps.FirstOrDefault(p => p.Name.ToUpper() == upperPropName); 

      foundProperty?.SetValue(result, prop.GetValue(map)); 
     } 

     return result; 
    } 

    // new instance without generic parameters 
    public object Create(Type type) 
    { 
     var result = Activator.CreateInstance(type); 

     // add all logic that you need 

     return result; 
    } 
} 

Và bây giờ bạn có thể sử dụng nhà máy này:

var factory = new SummaryFactory(); 
var carSummary = factory.Create<CarSummary>(); 
var carSummary2 = factory.Create<CarSummary>(car => { car.TotalMiles = 50; }); 
var carSummary3 = factory.Create<CarSummary>(new { TotalMiles = 50 }); 
var employeeSummary = factory.Create(typeof(EmployeeSummary)); 
+0

bạn có thể kết hợp hai phương pháp đầu tiên sử dụng một tham số tùy chọn và cũng kiểm tra cho null trên hành động – Nkosi

+0

@Nkosi gợi ý tốt, cảm ơn bạn – Fabjan

+0

Cần lưu ý rằng các phương pháp chung với ràng buộc 'new()' không phải là phương thức của nhà máy. Điều duy nhất như một phương thức có thể trả về là một thể hiện của loại bê tông * chính xác * mà bạn truyền vào, giới hạn các kiểu có một hàm tạo tham số. Về nguyên tắc OOP (như khớp nối lỏng), bạn hoàn toàn không đạt được gì. – Groo

1

Tùy thuộc vào các nhà thầu cho các đối tượng, bạn có thể làm điều này:

public interface ISummary 
{ } 

public class Bar : ISummary 
{ } 

public class SummaryFactory 
{ 
     public static TSummary CreateSummary<TSummary>() 
      where TSummary : new() 
    { 
     return new TSummary(); 
    } 
} 

public class Foo 
{ 
    public void AMethod() 
    { 
     var bar = SummaryFactory.CreateSummary<Bar>(); 
    } 
} 

Nhưng tôi không biết điều gì sẽ thực sự giúp bạn mua trừ khi người tạo trông rông.

Nếu đối tượng của bạn không có thông số nhà xây dựng, bạn có thể sử dụng mô hình chiến lược để tạo ra chúng thay vì các mô hình nhà máy, một cái gì đó như thế này:

public interface ISummary 
{ } 

public class CarSummary : ISummary 
{ 

    public CarSummary(int someParam) 
    { 

    } 
} 

public interface ISummaryStrategy 
{ 
    /// <summary> 
    /// 
    /// </summary> 
    /// <returns></returns> 
    ISummary Create(); 
} 

public class CarSummaryStrategy 
    : ISummaryStrategy 
{ 
    public ISummary Create() 
    { 
     return new CarSummary(42); //The Answer to the Ultimate Question of Life, the Universe, and Everything 
    } 
} 



public class Foo 
{ 
    private Dictionary< Type, ISummaryStrategy > _summaryStrategies; 
    public Foo() 
    { 
     this._summaryStrategies = new Dictionary< Type, ISummaryStrategy > 
     { 
      {typeof(CarSummary), new CarSummaryStrategy()} 
     }; 

    } 
    public void UseSummaries(Type summary) 
    { 
     var summaryImpl = this._summaryStrategies[summary].Create(); 
     // use the summary 
    } 
} 
1

Generics với một hạn chế new() chỉ làm cho khớp nối chặt chẽ hơn. Nếu bạn đã biết loại nào cần vượt qua làm tham số chung T và bạn biết phương thức sẽ trả về, thì điểm nào khi sử dụng nó?

// This is a *helper method* which will create a car summary. 
// No abstraction, no polymorphism, just a template helper method. 
var summary = CreateSummary<CarSummary>(carData); 

Nếu bạn cần một trừu tượng nhà máy, sau đó nó có nghĩa là phương pháp gọi điện thoại của bạn chỉ biết giao diện trở lại, và đó là nhà máy mà là vụ phải quyết định việc thực hiện thực tế.

Trong trường hợp của bạn, (tôi tin) bạn có một số loại lớp dữ liệu và bạn muốn phương pháp tạo bản tóm tắt thích hợp cho từng loại. I E. một cái gì đó như:

class EmployeesData : IEmployeesData 
{ ... } 

class CarsData : ICarsData 
{ ... } 

// at this point we don't know what `data` actually is 
IData data = GetDataFromSomewhere(); 

// so we cannot pass the concrete generic parameter here 
ISummary summary = GetSummary(data); 

Sau đó, những gì bạn cần là một loại chiến lược sẽ chọn triển khai đúng lúc chạy.Chiến lược với nhiều loại đầu vào khác nhau nên được đăng ký lúc khởi động chương trình (ở đâu đó bên trong thư mục gốc soạn thư hoặc tiêm qua DI), nhờ vậy bạn có cái gì đó như:

static readonly Dictionary<Type, Func<object, ISummary>> _strategies = 
     new Dictionary<Type, Func<object, ISummary>>(); 

public static void Register<T>(Func<T, ISummary> strategy) 
{ 
    _strategies[typeof(T)] = input => strategy((T)input); 
} 

public ISummary CreateSummary(object input) 
{ 
    var type = input.GetType(); 

    Func<object, ISummary> strategy; 
    if (!_strategies.TryGetValue(type, out strategy)) 
     throw new ArgumentException($"No strategy registered for type {type}"); 

    return strategy(input); 
} 

Vì vậy, đâu đó ở gốc thành phần của bạn, bạn sẽ phải bê tông phương pháp:

ISummary CreateEmployeeSummary(EmployeesData data) 
{ ... } 

ISummary CreateCarSummary(CarsData data) 
{ ... } 

// and finally register all concrete methods: 
Register<IEmployeesData>(d => CreateEmployeeSummary(d)); 
Register<ICarsData>(d => CreateCarsSummary(d)); 
Các vấn đề liên quan