这适用于城市建设者游戏,但该框架应该对任何请求和发送都有用。 基本上,您有供应商和请求者。当请求者在其需要的情况下运行不足时,会提出请求。然后每个滴答所有请求都被处理,适当的供应商将他们的东西发送给相应的请求者,每个人都很高兴。 我正在做的是尝试用泛型完成所有工作。我对泛型非常好但是暂时没有使用它们所以解决方案可能很简单。 这是一些代码:
public interface Requester<T> where T : Item
{
bool NeedsToRequest();
Request<T> LodgeRequest();
}
public interface Supplier<T> where T : Item
{
void Supply(Request<T> request);
}
public class Request<T> where T : Item
{
public Pile<T> Target;
public int Amount;
}
所有这些都集中在一个大的中介类中,该类处理请求制作和实现等等。
public abstract class ProductionHandler
{
public List<Supplier<Item>> Suppliers;
public List<Request<Item>> Requests;
public abstract bool TryRequest<T>(Request<T> request) where T : Item
}
也是相关的:
public class Pile<T> : List<T> where T : Item
{
public int Amount
{
get { return this.Count; }
}
}
最大的问题是按T类型对供应商进行排序。我想查看请求列表,获取其类型,从列表中找到匹配类型的供应商,并处理请求。 另一个问题是让我们说你有“花:项目”和“玫瑰:花”和“向日葵:花”。如果某些东西请求鲜花你想要发送它任何类型,所以在这种情况下只比较类型不会那么容易。 如果有人可以将我链接到一篇好文章或建议我如何使一切结构化,那将是非常感谢。
答案 0 :(得分:2)
可以帮助进一步发展的第一步是使用方差,例如Supplier<Rose>
可以投放到Supplier<Flower>
和Supplier<Item>
(反之亦然)。但要实现这一点,供应商必须是一个界面(ISupplier<out T>
)。更多信息:Covariance and Contravariance in Generics
这样,您可以保留ISupplier<Item>
的列表,但请确保添加了强列表的供应商。意味着列表仅包含ISupplier<Rose>
或ISupplier<Sunflower>
等项目的直接实现
拥有可转换的集合,您只需使用OfType<ISupplier<ItemType>>
即可获得所需的供应商。
要耦合请求,有几种可能性(例如,在ISupplier上有两种类型,或者让接口公开另一种类型的通用方法,让供应商按照添加的类型进行检查),但是最干净的方法是使用请求(IRequest<in T>
)的逆变接口,可以在接口定义中使用。
示例设置:
public interface ISupplier<out T>
{
int Supply(IRequest<T> request);
}
public interface IRequest<in T> //request is input and is contravariant so it can be used in the ISupplier definition. Roughly said it means that if a specific type is used, it can also be used as input for any child type
{
int Amount{get;set;}
}
public abstract class ProductionHandlerBase
{
public List<ISupplier<Item>> Suppliers = new List<ISupplier<Item>>(); //ISupplier is covariant so any more derrived type (than Item) is still valid
public IEnumerable<ISupplier<T>> GetSuppliers<T>() //helper function to make calls easier, but Suppliers could be used directly as well
{
return Suppliers.OfType<ISupplier<T>>();
}
public bool TryRequest<T>(IRequest<T> Request)
where T:Item
{
//example implementation. (neither optimized or necessariy logical, but it does show the expected types are used)
foreach(var sup in GetSuppliers<T>())
{
if(sup.Supply(Request) > 0 && Request.Amount == 0)
return true;
}
return false;
}
public void TestOutput()
{
Console.WriteLine(string.Join(", ", Suppliers));
}
}
class ProductionHandlerExample:ProductionHandlerBase{}
public class Request<T>:IRequest<T>{
public int Amount{get;set;}
}
public abstract class Supplier<T>:ISupplier<T>{
int pileAmount = 4; //just to have an example
public int Supply(IRequest<T> request) //example implementation
{
int cnt = Math.Min(request.Amount, pileAmount);
if(cnt==0)return 0;
pileAmount -= cnt;
request.Amount -=cnt;
return cnt;
}
public override string ToString() {return $"{typeof(T).Name}(s): {pileAmount}"; }
}
//items
public abstract class Item{}
public abstract class Flower:Item{}
public class Rose:Flower{}
public class SunFlower:Flower{}
public class Car:Item{}
//suppliers
public class Florist:Supplier<Flower>{} //implementation can still be on a class, as long as the collections are based on the covariant interface
public class Rosy:Supplier<Rose>{}
public class CarDealer:Supplier<Car>{}
使用示例:
var p = new ProductionHandlerExample();
p.Suppliers.Add(new Florist());
p.Suppliers.Add(new Rosy());
p.Suppliers.Add(new CarDealer());
//p.GetSuppliers<Flower>() -> Florist, Rosy
//p.GetSuppliers<Rose>() -> Rosy
//p.GetSuppliers<Item>() -> all items (Florist, Rosy, CarDealer)
//in the example setup, each supplier has a pile of 4
p.TestOutput(); //Flower(s): 4, Rose(s): 4, Car(s): 4
p.TryRequest(new Request<Rose>{Amount = 2}); //returns true
p.TestOutput(); //Flower(s): 4, Rose(s): 2, Car(s): 4
p.TryRequest(new Request<Car>{Amount = 5}); //returns false, there are only 4 cars
p.TestOutput(); //Flower(s): 4, Rose(s): 2, Car(s): 0
p.TryRequest(new Request<Flower>{Amount = 5}); //returns true, stock of both florist and Roses are used
p.TestOutput(); //Flower(s): 0, Rose(s): 1, Car(s): 0
在此示例实现中,不进行子类型检查。例如如果花店里的鲜花可能是玫瑰。那是因为这个例子假设花的类型实际上并不知道。如果已知,最好让一般(I)Supplier
使用通用的TryRequest方法,其中每个实现都会检查自己的库存(Pile.OfType<>
等)
答案 1 :(得分:0)
我认为这与您的TryRequest<T>(Request<T> request) where T : Item
方法有关。在Suppliers
实施中,您有T,因此您可以使用反射轻松地浏览var supplier = Suppliers.FirstOrDefault
( sup => sup.GetType()
.GenericTypeArguments[0] == typeof(T)
);
:
function sortByMutipleFields(...args: string[]) {
// takes a list of arguments representing sort fields
// if preceded by a ! then reverse order (!lastName for example)
// returns a function that works in Array.sort()
return (a: any, b: any): number => {
for (var index = 0; index < args.length; index++) {
let fieldLeft: string;
let fieldRight: string;
if (args[index].startsWith('!')) {
fieldLeft = b[args[index].slice(1)];
fieldRight = a[args[index].slice(1)];
} else {
fieldLeft = a[args[index]];
fieldRight = b[args[index]];
}
if (fieldLeft > fieldRight) { return 1 };
if (fieldLeft < fieldRight) { return -1 };
};
return 0;
}
}
正如你所看到的,这不是很漂亮,但我现在没有更好的选择。