2012-03-30 19 views
9

Tôi biết tôi không làm điều này đúng, nhưng tôi cũng biết có một cách để làm điều này. Tôi đang cố gắng để được như chung chung và trừu tượng nhất có thể, nếu không mã của tôi là sẽ nhận được thực sự lộn xộn. Vì vậy, tôi đang sử dụng mô hình chiến lược ở đây là địa ngục, đó là phương thức GetAggregateClient().Cách tốt nhất để làm lớp trừu tượng chung này trong C# là gì?

Tôi muốn có một lớp trừu tượng được gọi là AbstractAggregate, để nó sử dụng Generics. Loại sẽ được sử dụng là một loạt các lớp dữ liệu là BlogItem, ResourceItem và AskItem. Tất cả các lớp dữ liệu này đều được kế thừa từ ListItem.

Vì vậy, đó là thông tin cơ bản. Vấn đề ở đây là tôi muốn GetAbstractAggregate() trả về một thể hiện của một trong các lớp máy khách thực hiện AbstractAggregate với kiểu mục được chỉ định tùy thuộc vào enum được truyền vào. Tuy nhiên, tôi không thể trả về một "AbstractAggregate". Trình biên dịch sẽ không cho phép tôi và điều đó có ý nghĩa vì lớp AbstractAggregateFactory không phải là một generic.

Có ai có cách tốt nhất để làm điều này không?

Cảm ơn rất nhiều.

public static class AggregateHelper 
{ 
    public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources } 
} 

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient(AggregateHelper.AggregateTypes type) 
    { 
     switch (type) 
     { 
      case AggregateHelper.AggregateTypes.AskTankTruck: 
       return new AskTankTruckAggregate<AskItem>(); 
      case AggregateHelper.AggregateTypes.TankTruckBlog: 
       return new TankTruckBlogAggregate<BlogItem>(); 
      case AggregateHelper.AggregateTypes.Resources: 
       return new ResourcesAggregate<ResourceItem>(); 
      default: 
       throw new AggregateDoesNotExistException(); 
     } 
    } 
} 

public abstract class AbstractAggregate<T> 
{ 
    public abstract List<T> GetAggregate(Guid[] resourcetypes); 

    public abstract T GetSingle(string friendlyname); 


} 

public class AskTankTruckAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

Trả lời

3

vấn đề, trình biên dịch phàn nàn về
... là bạn có một phương pháp đó là ' mở '(T) - và bạn đang quay trở lại đóng chung (với <AskItem> vv), loại bê tông thực sự.
tức là bạn phải trả lại ... <T> - ... và bạn có thể thực hiện điều đó bằng phương pháp - bất kể nhà máy không phải là chung chung, phương pháp có thể vẫn còn.
Đối với cách tốt nhất để làm điều đó,
đó là câu hỏi 'thiết kế' hơn - và một câu chuyện dài hơn một chút,
Tôi không hoàn toàn chắc chắn những gì bạn đang cố gắng đạt được (có thể một số câu chuyện cơ bản, cách nhiều loại bạn có thể có v.v.),

Trước tiên, bạn không nên (nói chung, thực hành tốt nhất hoặc yếu tố 'cảm thấy tốt')
kế thừa các mục của bạn từ ListItem - sử dụng một số lớp cơ sở khác của bạn - và nếu bạn cần một bộ sưu tập sử dụng một bộ sưu tập chung như List<T> - hoặc tạo bản thực thi IList của riêng bạn, v.v.

Thứ hai, điều là bạn không cần mọi thứ chung chung. Trình tổng hợp cơ sở của bạn là chung nhưng các lớp tùy chỉnh thì không, thường là, ví dụ: như thế này ...

abstract class ItemBase { } 
class AskItem : ItemBase { } 
class BlogItem : ItemBase { } 
class ProvderA : ProviderBase<AskItem> 
{ 
    public override AskItem Get() 
    { 
     throw new NotImplementedException(); 
    } 
} 
class ProvderB : ProviderBase<BlogItem> 
{ 
    public override BlogItem Get() 
    { 
     throw new NotImplementedException(); 
    } 
} 
abstract class ProviderBase<T> where T : ItemBase 
{ 
    public abstract T Get(); 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     ProviderBase<AskItem> provider = GetProvider<AskItem>(); 
     var item = provider.Get(); 
    } 
    static ProviderBase<T> GetProvider<T>() where T : ItemBase 
    { 
     if (typeof(T) == typeof(AskItem)) 
      return (ProviderBase<T>)(object)new ProvderA(); 
     if (typeof(T) == typeof(BlogItem)) 
      return (ProviderBase<T>)(object)new ProvderB(); 
     return null; 
    } 
} 

... đó là một triển khai.
Về cơ bản, không phải mọi thứ 'chung' luôn là cách tốt nhất. Bạn phải có đủ lý do hoặc 'loại' không được sử dụng. Như với chung bạn cũng phải trả một mức giá nhất định. Việc sử dụng chung generics cho thế giới phi generics thường phức tạp, và liên quan đến sự phản chiếu nếu các kiểu của bạn không thể suy ra được bằng cách sử dụng, vv ..
Lỗi IMO làm cho mỗi nhà cung cấp trở nên chung chung - vì nó chỉ chấp nhận một loại (mỗi bê tông), trong khi cơ sở là chung chung. Vì vậy, như trên. Thông thường, chung chung cũng bị hạn chế cho mỗi giao diện nơi/nơi bạn có thể.
Nhưng sau đó bạn có vấn đề khi quay trở lại ngữ cảnh chung từ một lớp không chung chung có hiệu quả không phải là thẳng (cũng có trong tâm trí có các loại giá trị vì bạn phải đối xử khác đôi khi, thường xuyên) và ngược lại cũng vậy.
Do đó bạn cần một cái gì đó như đúc (đối tượng) đầu tiên.
Tôi muốn sử dụng loại phương pháp tiếp cận IOC ở đây - ví dụ: nhìn vào autofac (Tôi không liên quan nhưng tôi thích cách thức hoạt động, khung làm đẹp). Trong trường hợp mà bạn muốn làm một cái gì đó giống như ...

 container.Register<ProviderBase<AskItem>>(c=> new ProvderA()); 
     container.Register<ProviderBase<BlogItem>>(c => new ProvderB()); 

     // and query later... 

     ProviderBase<AskItem> provider = container.Resolve<ProviderBase<AskItem>>(); 

hy vọng điều này giúp một số ...

+0

cảm ơn lời giải thích chi tiết. ban đầu tôi đã chọn một câu trả lời khác, nhưng bạn đã thuyết phục tôi. cảm ơn đã giúp đỡ! – apexdodge

+0

np :) - có rất nhiều cách/câu trả lời, chỉ cần giữ cho nó hợp lý (mỗi bit thường có mục đích của nó hoặc không đảm bảo một nơi) và bạn sẽ ổn. Và hãy xem IOC, autofac, bạn sẽ thích điều đó (nhiều hơn Generics :) – NSGaga

1

Tôi không chắc tôi hiểu những gì bạn đang cố gắng để đạt được nhưng có lẽ đó là một cái gì đó như thế này

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient<T>() 
    { 
     if(T is AskItem) return new AskTankTruckAggregate(); 
     if(T is BlogItem) return new TankTruckBlogAggregate(); 
     if(T is ResourceItem) return new ResourcesAggregate(); 
    } 
} 

public abstract class AbstractAggregate<T> 
{ 
    public abstract List<T> GetAggregate(Guid[] resourcetypes); 

    public abstract T GetSingle(string friendlyname); 
} 

public class AskTankTruckAggregate : AbstractAggregate<AskItem> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate : AbstractAggregate<ResourceItem> 
{ 
    //not implemented yet 
} 
+0

Tôi không nghĩ rằng bạn có thể làm 'T là BlogItem' - bạn cần có một giá trị của T - hoặc 'typeof (T) Equals (typeof (BlogItem))' hoặc một cái gì đó - giống như một sidenote – NSGaga

+0

@NSGaga: Vâng, có lẽ bạn đã đúng. – Gebb

1

Tôi đang cố gắng để được như chung chung và trừu tượng càng tốt, nếu không tôi mã sẽ nhận được lộn xộn thực sự.

đây là quan niệm sai lầm. là chung/trừu tượng thực sự có thể làm phức tạp một vấn đề khác đơn giản. Chìa khóa để làm sạch mã là đóng gói. nhiều khác biệt mà thừa kế hoặc generics.

Trong trường hợp này, tôi nghĩ rằng bố cục sẽ là lựa chọn tốt hơn, chứ không phải là thừa kế. với một bộ các bộ điều hợp, bạn có thể có một đối tượng chung mà mỗi thực thể có thể được đặt vào. ví dụ:

interface ICommon { ... } 

class AskAdaptor: ICommon 
{ 
    private readonly Ask ask; 
    publick AskAdaptor(Ask ask) 
    { 
     this.ask = ask; 
    } 
} 

class AskAdaptor: ICommon 
{ 
    private readonly Blog blog; 
    publick AskAdaptor(Blog blog) 
    { 
     this.blog = blog; 
    } 
} 

class AskAdaptor: ICommon 
{ 
    private readonly Resource resource; 
    publick AskAdaptor(Resource resource) 
    { 
     this.resource = resource; 
    } 
} 

class CommonAggregate 
{ 
    public void Add(ICommon common) 
    { 
     .... 
    } 
} 
1

Làm thế nào về điều này:

public static class AggregateHelper 
{ 
    public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources } 
} 

public class AskItem { } 
public class BlogItem { } 
public class ResourceItem { } 

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient<T> 
     (AggregateHelper.AggregateTypes type) 
    { 
     switch (type) 
     { 
      case AggregateHelper.AggregateTypes.AskTankTruck: 
       return new AskTankTruckAggregate<T>(); 
      case AggregateHelper.AggregateTypes.TankTruckBlog: 
       return new TankTruckBlogAggregate<T>(); 
      case AggregateHelper.AggregateTypes.Resources: 
       return new ResourcesAggregate<T>(); 
      default: 
       throw new ArgumentException(); 
     } 
    } 
} 

public abstract class AbstractAggregate<T> 
{ 
    public abstract List<T> GetAggregate(Guid[] resourcetypes); 
    public abstract T GetSingle(string friendlyname); 
} 

public class AskTankTruckAggregate<T> : AbstractAggregate<T> 
{ 
    public override List<T> GetAggregate(Guid[] resourcetypes) 
    { 
     throw new NotImplementedException(); 
    } 

    public override T GetSingle(string friendlyname) 
    { 
     Console.WriteLine(friendlyname); 
     Type whats_t = typeof(T); 
     return default(T); 
    } 
} 

public class TankTruckBlogAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

Ví dụ:

AbstractAggregate<BlogItem> foo3 = 
    AbstractAggregateFactory.GetAggregateClient<BlogItem>(AggregateHelper.AggregateTypes.AskTankTruck); 
foo3.GetSingle("test"); 
0

Một điều đó là có thể rõ ràng là thiết kế của bạn là hơi thiếu sót. Một chuyển đổi trên loại không phải là điều tốt nhất để làm trong một phương pháp chung mà đánh bại mục đích của nó. Nhưng điều không rõ ràng là mục đích của các lớp học của bạn là gì.

Một số suy đoán:

1) Thấy lớp cặp bạn AskItemAskTankTruckAggregate<T> vv Tôi không nghĩ rằng sau này có được một lớp chung, đó là một lớp rất cụ thể, chặt chẽ cùng với AskItem. Tôi sẽ thiết kế lại nó như

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem 
    { 
     //use reflection to find the type that inherits AbstractAggregate<T> 

     //instantiate the type 

     //cast to AbstractAggregate<T> and return 
    } 
} 

public class AskTankTruckAggregate : AbstractAggregate<AskItem> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate : AbstractAggregate<ResourceItem> 
{ 
    //not implemented yet 
} 

Gọi nó thích:

AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc 

2) Một cách khác: giao công việc sáng tạo tổng hợp để ListItems của bạn.

public abstract class ListItem //or interface 
{ 
    protected abstract object Create(); 
} 
public class AskItem : ListItem { //implement to return AskTankTruckAggregate 
} 
public class BlogItem : ListItem { //implement to return TankTruckBlogAggregate 
} 
public class ResourceItem : ListItem { //implement to return ResourcesAggregate 
} 

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem, new() 
    { 
     return (AbstractAggregate<T>)new T().Create(); 
    } 
} 

public class AskTankTruckAggregate : AbstractAggregate<AskItem> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate : AbstractAggregate<ResourceItem> 
{ 
    //not implemented yet 
} 

Gọi nó thích:

AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc 

3) Hoặc như nhau, nhưng làm cho nó mạnh mẽ hơn một chút đánh máy, với việc sử dụng Generics:

public abstract class ListItem<T> where T : ListItem<T> //or interface 
{ 
    protected abstract AbstractAggregate<T> Create(); 
} 
public class AskItem : ListItem<AskItem> { //implement to return AskTankTruckAggregate 
} 
public class BlogItem : ListItem<BlogItem> { //implement to return TankTruckBlogAggregate 
} 
public class ResourceItem : ListItem<ResourceItem> { //implement to return ResourcesAggregate 
} 

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem, new() 
    { 
     return new T().Create(); 
    } 
} 

public class AskTankTruckAggregate : AbstractAggregate<AskItem> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate : AbstractAggregate<ResourceItem> 
{ 
    //not implemented yet 
} 

Gọi nó như:

AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc 

4) Cuối cùng, có thể khiến loại trả lại ít chung chung hơn? Liên quan đến trường hợp chuyển đổi, tôi không thích nó.

public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources } 

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate GetAggregateClient(AggregateTypes type) 
    { 
     switch (type) 
     { 
      case AggregateTypes.AskTankTruck: 
       return new AskTankTruckAggregate<AskItem>(); 
      case AggregateTypes.TankTruckBlog: 
       return new TankTruckBlogAggregate<BlogItem>(); 
      case AggregateTypes.Resources: 
       return new ResourcesAggregate<ResourceItem>(); 
      default: 
       throw new AggregateDoesNotExistException(); 
     } 
    } 
} 

public abstract class AbstractAggregate 
{ 

} 

public abstract class AbstractAggregate<T> : AbstractAggregate 
{ 

} 

//or change the definition to AskTankTruckAggregate : AbstractAggregate<AskItem> 
public class AskTankTruckAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

//or change the definition to TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
public class TankTruckBlogAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

//or change the definition to ResourcesAggregate : AbstractAggregate<ResourceItem> 
public class ResourcesAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

Gọi nó thích:

AbstractAggregateFactory.GetAggregateClient(AggregateTypes.AskTankTruck); //etc 

Imo, phương pháp này là tồi tệ hơn so với phương pháp phản xạ. Dễ dàng quên một số kiểm tra enum trong tương lai.


Tất cả, thứ 3 trông đẹp nhất cho đôi mắt của tôi, nhưng lại không biết mục tiêu thiết kế của bạn, rất khó dự đoán. Một vài gợi ý:

  1. Tên nhà máy của bạn nghe tốt hơn như AggregateFactory. "Tóm tắt" trong nó làm cho nó thêm về thực hiện.

  2. Trong trường hợp bạn cần enum để biểu thị loại, đừng đặt lồng nhau. Các loại công cộng lồng nhau khó gọi hơn. Đưa ra lớp tĩnh gói (như trong phương pháp thứ 5 của tôi).

  3. Đổi tên lớp cơ sở là Aggregate<T> hoặc . Một lần nữa "Tóm tắt" trong nó làm cho nó thêm về thực hiện, khá vô dụng.