肯定这不是最好的标题。我正在创建一个系统来生成数学问题。开发人员必须实现两个接口:
Problem
:这包含需要生成问题的属性。Configuration
:这是生成Problem
。这些是接口:
public abstract class Problem
{
}
public abstract class Configuration
{
}
这是BinaryProblem的一个例子。
public class BinaryProblem : Problem
{
public decimal X { get; set; }
public decimal Y { get; set; }
public BinaryProblem(decimal x, decimal y)
{
this.X = x; // Number 1
this.Y = y; // Number 2
}
}
public class BinaryProblemConfiguration : Configuration
{
// Range for X
public int XMin { get; set; }
public int XMax { get; set; }
// Range for Y
public int YMin { get; set; }
public int YMax { get; set; }
public BinaryProblemConfiguration() { }
}
你能看到问题与配置之间的界限吗?我需要放置许多实现这两个接口的模块。
所以,我需要一种方法来生成它们。我在想创建一个抽象类,其中包含:
protected static Random
:几乎所有配置都需要一个随机类来创建数字(I.E. random.Next(X1, Y1);
)。并且必须保持静态,因为总是需要使用相同的种子创建数字。public abstract TProblem Generate(TConfiguration config); // where : TProblem : Problem, new(), TConfiguration : Configuration
在每个问题类型中实现这个抽象类。
我的问题是:这是开始解决此解决方案的好方法,还是我必须做的其他解决方案?
编辑:我尝试的一个例子是:
这是我的抽象类,我的意思是我的想法是当你实例化这个类时,你指定了通用值:
public interface IProblemFactory
{
Problem CreateProblem();
}
public abstract class ProblemBaseFactory<TProblem, TConfiguration> : IProblemFactory
where TProblem : Problem
where TConfiguration : Configuration
{
private const int SEED = 100;
protected TConfiguration _config;
protected static Random _random;
public ProblemBaseFactory(TConfiguration config)
{
_config = config;
if (_random == null) _random = new Random(SEED);
}
public void SetSeed(int newSeed)
{
_random = new Random(newSeed);
}
public Problem CreateProblem()
{
return CreateProblem(_config);
}
public abstract TProblem CreateProblem(TConfiguration config);
}
public class BinaryProblemFactory : ProblemBaseFactory<BinaryProblem, BinaryProblemConfiguration>
{
public override BinaryProblem CreateProblem(BinaryProblemConfiguration config)
{
var x = GenerateValueInRange(_config.Range1);
var y = GenerateValueInRange(_config.Range2);
return new BinaryProblem(x, y, Operators.Addition);
}
private decimal GenerateValueInRange(Range<int> range)
{
return _random.Next(range.MinValue, range.MaxValue);
}
}
答案 0 :(得分:2)
我认为聚合一起使用的值是很好的。在你的情况下,对象Range将是有用的。类似的东西(没有验证min&lt; = max):
public class Range<T>
{
public Range(T min, T max)
{
Min = min;
Max = max;
}
public T Min { get; private set; }
public T Max { get; private set; }
}
之后,BinaryProblemConfiguration将如下所示:
public class BinaryProblemConfiguration
{
public Range<int> XRange { get; set; }
public Range<int> YRange { get; set; }
}
您实际实施的是产品工厂。因此,我对Intermediary的描述名称不是很明确:
public interface IProblemFactory
{
Problem CreateProblem();
}
为每种类型的产品创建工厂。每个工厂都知道它创建了什么类型的产品以及它需要什么类型的配置。 E.g:
public class BinaryProblemFactory : IProblemFactory
{
private BinaryProblemConfiguration _config;
private Random _random;
public BinaryProblemFactory(BinaryProblemConfiguration config)
{
_config = config;
// or you can use const seed here
_random = new Random(DateTime.Now.Millisecond);
}
public override Problem CreateProblem()
{
var x = GenerateValueInRange(_config.XRange);
var y = GenerateValueInRange(_config.YRange);
return new BinaryProblem(x, y);
}
private decimal GenerateValueInRange(Range<int> range)
{
return _random.Next(range.Min, range.Max);
}
}
工厂创建:
BinaryProblemConfiguration config = new BinaryProblemConfiguration();
config.XRange = new Range<int>(0, 100);
config.YRange = new Range<int>(-50, 50);
IProblemFactory problemFactory = new BinaryProblemFactory(config);
将创建的问题工厂作为IProblemFactory传递到某处:
Problem problem = problemFactory.CreateProblem();
也没有特别需要配置对象。我认为产品的创造者应该知道如何创造产品。所以我宁愿把XRange和YRange的属性添加到工厂:
BinaryProblemFactory binaryProblemFactory = new BinaryProblemFactory();
binaryProblemFactory.XRange = new Range<int>(0, 100);
binaryProblemFactory.YRange = new Range<int>(-50, 50);
答案 1 :(得分:0)
不确定,如果我理解你的问题,但无论如何我会尝试对此发表意见。希望它有所帮助。
我相信你选择了错误的做法。 - 你有两个班级,但他们根本不沟通(即使他们应该) - 是的,你已经创建了派生的抽象类,但是在这个特殊情况下我没有看到原因为什么。它们没有定义任何内容,它们不强制执行任何逻辑来派生类。在创建界面时,您希望有人从中派生出来实现它。你无法真正实现一个空的类/接口。
首先,我建议解决这个问题。如果要实现它们,请创建需要某些方法或属性的接口。这样您就可以更轻松地开发主应用程序,因为您会知道,无论其他开发人员创建什么问题,他都需要使用您可以使用的某些方法来实现您的接口。如果允许实现空接口,则无法确定结果将是什么以及期望什么。你不能依赖它们表现得很好(或至少你不应该)。
其次,不确定您是否知道它,但是当您使用模块(问题+配置作为一个模块)时,将每个模块放在一个单独的.cs文件中。这样,您可以拥有几乎无限数量的内容,并且仍然可以轻松维护您的应用程序。
第三,我建议使用这样的接口在这些类之间建立一些关系(和通信):
public interface IProblem
{
IProblemConfiguration Config;
// other needed methods or properties
}