Я даже не уверен, что искать в связи с этой проблемой, поэтому я решил опубликовать это здесь.
Допустим, у меня есть несколько интерфейсов, таких как ...
/// <summary>
/// All interesting classes will implement this interface
/// </summary>
interface IMasterInterface {}
/// <summary>
/// Interface to represent someone that creates / produces goods
/// </summary>
interface IProduceGoods : IMasterInterface { int Prop1 {get;} }
/// <summary>
/// Interface to represent someone that buys / consumes goods
/// </summary>
interface IConsumeGoods : IMasterInterface { int Prop2 {get;} }
/// <summary>
/// Interface to represent someone that stores goods
/// </summary>
interface IStoreGoods : IMasterInterface { double Prop3 {get;} string name {get;}}
/// <summary>
/// Interface to represent someone that enjoys looking at goods
/// </summary>
interface IEnjoyLookingAtGoods : IMasterInterface { int Prop4 {get;} DateTime Prop5 {get;} }
Теперь у меня есть какая-то комбинация, которую я знаю сегодня, что-то вроде:
/// <summary>
/// Class to represent a farm which grows and stores crops
/// </summary>
class Farm : IProduceGoods, IStoreGoods {/*...*/}
/// <summary>
/// Class to represent a merchant who buys goods and stores them
/// </summary>
class Merchant : IConsumeGoods, IStoreGoods {/*...*/}
/// <summary>
/// Window Shopper represents someone who doesn't buy anything and only looks
/// </summary>
class WindowShopper : IEnjoyLookingAtGoods{ /*...*/ }
Теперь я счастлив, что у меня есть несколько моих классов, но завтра, я думаю, было бы неплохо также иметь класс, где кто-то фактически покупает у Продавца, так что я бы пошел к своему коду и добавить
/// <summary>
/// Princesses have lots of money to buy stuff and lots of time to look at stuff
/// </summary>
class Princess : IEnjoyLookingAtGoods, IConsumeGoods {/*...*/}
Так вот, я не думаю, что мне нужно это делать ...
Я бы хотел иметь фабричную (или похожую) вещь и сказать:
IMasterInterface princess = MyFactory.Create(IEnjoyLookingAtGoods, IEnjoyLookingAtGoodsParameters, IConsumeGoods, IConsumeGoodsParameters)
/// This should be true
((princess is IEnjoyLookingAtGoods) && (princess is IConsumeGoods))
По сути, я хотел бы сообщить фабрике, какие интерфейсы использовать для создания объекта. У меня есть контейнеры, которые имеют списки IMasterInterface
/// <summary>
/// My container class for interesting objects
/// </summary>
class InterestingObjectContainer
{ public ReadOnlyCollection<IMasterInterface> InterestingObjects {get;} }
Теперь, вот где лежит вопрос. Причиной того, что все интересные классы реализовали IMasterInterface, была возможность иметь список и использовать более специфические интерфейсы в качестве фильтров. Возможно, следующее станет более понятным:
/// <summary>
/// I want to see the net population of producers and get there total production
/// </summary>
class ProducerProductionCalculator
{
// THIS IS WHERE THE MEAT OF THE QUESTION RESIDES!
ProductionResults Calculate(InterestingObjectContainer interestingObject)
{
List<IProduceGoods> producers = interestingObject.InterestingObjects.OfType<IProduceGoods>(); // Perhaps more interest LINQ
return DoSomethingWithListToAggregate(producers);
}
}
Отфильтровав более конкретный интерфейс, теперь я могу рассчитывать на все объекты, переданные
DoSomethingWithListToAggregate (производители ICollection)
имеющие методы / свойства класса IProduceGoods.
Я думал о реализации этого с помощью словарей и поиска свойств строки, но мне кажется, что я могу написать более строго типизированный код таким образом и убедиться, что простая орфографическая ошибка где-то не испортит все.
Во всяком случае, я думаю, что резюме:
Это плохой способ реализации переменных свойств объекта и, если да, то что будет лучше. Если нет, то есть ли способ создать объекты на фабрике, как я пытался объяснить выше?
EDIT:
Я вижу некоторые мысли о том, чтобы сделать это, и это круто. Мне было интересно, как создать фабрику, которая принимает аргументы интерфейса, который имеет только свойства и свойства имеют только геттеры (я думаю, это важный момент) вместе со значениями свойств для свойств и возвращает объект, который реализует интерфейс и имеет все свойства определены.
Например,
/// <summary>
/// Factory to create any combination of properties
/// </summary>
class FactoryForInterestingObjects
{
public static IMasterInterface Create(
List<KeyValuePair</*what goes here is the interface that I want to use,
what goes here are the parameter values that
should be returned by the getter */>> );
}
Я бы передал фабрике все интерфейсы и их значения параметров, и он создал бы некоторый класс, который реализует эти интерфейсы и имеет эти значения. Надеюсь, это немного понятнее?
РЕДАКТИРОВАТЬ 2: Как использовать Decorator?
Из того, что я вижу в декораторе, вы можете расширить функциональность объекта. Это круто. Однако вы должны заранее знать, как вы расширяете эту функциональность. Вы не можете сделать это произвольно.
Учтите, что моя кодовая база такая же, как и выше, и я хочу использовать декоратор.
Я бы сказал:
// Edited to be correct
class EnjoyLookingDecorator : IEnjoyLookingAtGoods
{
private IMasterInterface instance;
public EnjoyLookingDecorator(IMasterInterface wrappedObject)
{ this.instance = wrapped Object;}
#region Implementation of IEnjoyLookingAtGoods
/*...*/
#endregion
}
РЕДАКТИРОВАТЬ 4:
Я все еще не думаю, что это сработает. В вашем примере я теряю содержащийся интерфейс классов, я должен перенаправить его вниз. Например,
class EnjoyLookingDecorator : IEnjoyLookingAtGoods
{
private IMasterInterface instance;
public EnjoyLookingDecorator(IMasterInterface concrete)
{ this.instance = concrete;}
#region Implementation of IEnjoyLookingAtGoods here
/*...*/
#endregion
bool Is<T>() //this should be in the IMasterInterface
{
return this is T or instance is T;
}
}
class ConsumesGoodsDecorator : IConsumeGoods
{
private IMasterInterface instance;
public ConsumesGoodsDecorator (IMasterInterface concrete)
{ this.instance = concrete;}
#region Implementation of IConsumeGoods here
/*...*/
#endregion
bool Is<T>()
{
return this is T or instance is T;
}
}
поэтому, когда вы d
IMasterInterface princess = new MasterClass() //whatever your concrete type is named
princess = new ConsumesGoodsDecorator(new EnjoyLookingDecorator(princess))
вы больше не можете делать princess.PropertyOnIEnjoyLookingDecorator. Интерфейс вы теряете все эти свойства. Это не то, что я хочу. Единственный способ сохранить свойства - это перенаправить
class ConsumesGoodsDecorator : IConsumeGoods, IEnjoyLookingAtGoods
{
private IMasterInterface instance;
public ConsumesGoodsDecorator (IMasterInterface concrete)
{ this.instance = concrete;}
#region Implementation of IConsumeGoods here
/*...*/
#endregion
#region Redirect all the IEnjoyLookingAtGoods Property Getters to instance
/* ... */
#endregion
bool Is<T>()
{
return this is T or instance is T;
}
}
Выполнив перенаправление, мы должны реализовать интерфейс. Тогда комбинации должны иметь код, который я стараюсь избегать. У меня нет ограничений на комбинации интерфейсов.
РЕДАКТИРОВАТЬ 5:
Возможно, мне все еще не ясно в моем вопросе. Представьте интерфейсы такими, как они указаны выше, с заполненными свойствами.
Если бы фабрика могла сделать что-то вроде этого:
/// <summary>
/// Factory to create any combination of properties
/// </summary>
class FactoryForInterestingObjects
{
public static IMasterInterface Create(
List<KeyValuePair<Type t, ArgSet customArguments>> interfaces))
{
object baseObject;
foreach(KeyValuePair<Type, ArgSet> interface in interfaces)
{
AddInterface(interface, object);
}
}
private static void AddInterface(KeyValuePair<Type, ArgSet> interface, ArgSet arguments)
{
// Delegate this to someone else
if(interface.Key is typeof(IProduceGoods))
{
IProduceGoodsExtensions.AddInterface(o, interface.value);
}
}
}
public static class IProduceGoodsExtensions
{
public static void AddInterface(object o, ArgSet arguments)
{
// do something to object to make it implement IProductGoods
// and make all the getters return the arguments passed in ArgSet
}
}
Я понимаю, что это не так, как на самом деле будет работать, но иллюстрирует мысль, которую я пытаюсь сделать. Я хочу, чтобы объект реализовал динамическую комбинацию интерфейсов и имел значения по умолчанию для сеттеров.
Даже если бы я мог сделать что-то наподобие фабрики, напишите текстовый файл с кодом:
/// <summary>
/// Auto Generated by Factory to create a new type on the fly
/// </summary>
class ClassImplementingIProduceGoodsAndIEnjoyLookingAtGoods : IProduceGoods, IEnjoyLookingAtGoods
{
// From IProduceGoods
public int Prop1 {get; private set;}
// From IEnjoyLookingAtGoods
public int Prop4 {get; private set;}
public DateTime Prop5 {get; private set;}
public ClassImplementingIProduceGoodsAndIEnjoyLookingAtGoods(int prop1, int Prop4 , DateTime Prop5)
{
this.Prop1 = prop1; this.Prop4 = Prop4; this.Prop5 = Prop5;
}
}
Затем скомпилируйте класс и как-нибудь разрешите мне создавать его экземпляры. Это то, что я ищу. Надеюсь, это имеет больше смысла.
РЕДАКТИРОВАТЬ 6:
Это решение, с которым я, вероятно, пойду, так как на данный момент я не вижу альтернативы.
//Update Master Interface
interface IMasterInterface
{
bool Is(Type t);
IMasterInterface As(Type t);
}
/// <summary>
/// Class to build up a final object
/// </summary>
class CompositionObject : IMasterInterface
{
ICollection<IMasterInterface> parts;
CompositionObject(IMasterInterface object){ parts = new List<IMasterInterface(object);}
bool Is(Type t)
{
foreach(IMasterInterface part in parts)
{ if (part is t) return true; // not sure on this off top of head
}
return false;
}
IMasterInterface As(Type t)
{
foreach(IMasterInterface part in parts)
{ if(part is t) return part; }
}
bool Add(IMasterInterface interface)
{ this.Is(typeof(interface)) return false; // don't add again
this.parts.Add(interface) }
}
Теперь моя фабрика может просто возвращать эти составные объекты, и, пока вызывается As, я могу безопасно отключиться. Я чувствую, что, возможно, есть способ использовать дженерики, чтобы избежать кастинга.
Любые конкретные классы, реализующие IMasterInterface, могут просто возвращать себя при вызове As.
РЕДАКТИРОВАТЬ 3:
Спасибо всем за комментарии. Я рад, что опубликовал свое незнание шаблона; D Спасибо за разъяснения! Я люблю этот сайт и всех вас, милые люди там !!