Jedno jest ewentualnie jasne jest to, że projekt jest nieco wadliwa. Typ przełączania nie jest najlepszą rzeczą do zrobienia w ogólnej metodzie, która pokonuje jego cel. Ale nie jest jasne, jaki jest cel twoich zajęć.
Niektóre spekulacje:
1) widząc klas pary AskItem
i AskTankTruckAggregate<T>
etc nie sądzę, ten ostatni musi być rodzajowe klasy, jest to bardzo specyficzna klasa, ściśle sprzężony AskItem
. Chciałbym zaprojektować go jak
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
}
nazwać to lubią:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
2) inny sposób: przekazać łączną tworzenie miejsc pracy do ListItems.
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
}
nazwać to lubią:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
3) lub takie same, ale sprawiają, że nieco silniej wpisane, z wykorzystaniem leków generycznych:
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
}
połączeń to:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
4) Na koniec może być mniej typowy typ zwrotu? Obejmuje przypadek przełącznika, nie podoba mi się to.
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
}
nazwać to lubią:
AbstractAggregateFactory.GetAggregateClient(AggregateTypes.AskTankTruck); //etc
Imo, podejście to jest gorsze niż podejście refleksji. Łatwo zapomnieć o wyliczeniach w przyszłości.
Ze wszystkich, trzeci wygląda najlepiej w moich oczach, ale znowu nie znając swojego projektu, jest bardzo trudny do przewidzenia. Kilka sugestii:
Twoja nazwa fabryczna brzmi lepiej jak AggregateFactory
. "Abstrakcja" w nim sprawia, że bardziej na temat realizacji.
W przypadku potrzeby wyliczenia typu, nie należy go zagnieżdżać. Zagnieżdżone typy publiczne są trudniejsze do wywołania. Wyjmij pakującą klasę statyczną (jak w moim piątym podejściu).
Zmień nazwę swojej klasy bazowej na Aggregate<T>
lub . Ponownie "abstrakcja" w nim sprawia, że bardziej na temat realizacji, zupełnie niepotrzebne.
dzięki za szczegółowe wyjaśnienie. początkowo wybrałem inną odpowiedź, ale mnie przekonałeś. dzięki za pomoc! – apexdodge
np :) - jest wiele sposobów/odpowiedzi, po prostu trzymaj się logiki (każdy bit zwykle ma swój cel lub nie gwarantuje miejsca) i wszystko będzie dobrze. I spójrz na IOC, autofac, spodoba ci się (więcej niż generics :) – NSGaga