2401d,d随机选择类

原文
我有一个许多类实现的接口,我想随机选择其中一个实现.还有两个约束:首先,不是均匀分布,所有类都可定义被选中的机会(反映在"weight()"函数中).而且根据运行时信息,并非所有类都可用.

我搞了个最小工作示例,但它很重(特别是因为有中间枚举),可更漂亮,更易于理解(也许用模板插件等编译时操作).
可否改进?

import std.stdio;
import std.array;
import std.algorithm;
import std.conv;
import std.random;
interface Parent
{
    
    
    void doWork();
    static int weight();
    static Parent from(Implem impl)
    {
    
    
        final switch (impl)
        {
    
    
        case Implem.IMPLEM_1:
            return new Implem1();
        case Implem.IMPLEM_2:
            return new Implem2();
        case Implem.IMPLEM_3:
            return new Implem3();
        }
    }
}
class Implem1 : Parent
{
    
    
    void doWork()
    {
    
    
        writeln("From Implem 1");
    }
    static int weight()
    {
    
    
        return 3;
    }
}
class Implem2 : Parent
{
    
    
    void doWork()
    {
    
    
        writeln("From Implem 2");
    }
    static int weight()
    {
    
    
        return 2;
    }
}
class Implem3 : Parent
{
    
    
    void doWork()
    {
    
    
        writeln("From Implem 3");
    }
    static int weight()
    {
    
    
        return 3;
    }
}
enum Implem
{
    
    
    IMPLEM_1,
    IMPLEM_2,
    IMPLEM_3
};

Implem[] availableImplems()
{
    
    
    bool runtimeCondition = true;
    if (runtimeCondition)
        return [Implem.IMPLEM_1, Implem.IMPLEM_2];
    else
        return [Implem.IMPLEM_2, Implem.IMPLEM_3];
}
int getWeight(Implem implem)
{
    
    
    final switch (implem)
    {
    
    
    case Implem.IMPLEM_1:
        return Implem1.weight();
    case Implem.IMPLEM_2:
        return Implem2.weight();
    case Implem.IMPLEM_3:
        return Implem3.weight();
    }
}
int[] getAllWeights(in Implem[] availableImplems)
{
    
    
    return availableImplems.map!(implem => implem.getWeight()).array;
}
Parent drawAtRandom()
{
    
    
    const Implem[] available = availableImplems();
    const int[] weights = getAllWeights(available);
    const Implem drawn = available[dice(weights)];
    return Parent.from(drawn);
}
void main()
{
    
    
    Parent p = drawAtRandom();
    p.doWork();
}

我会用编译时枚举标记每个实现,并用带CRTP[1]编译时内省,并根据期望分布选择类来自动生成代码.
1维基CRTP
如下:

import std.stdio;
interface MyIntf {
    
    
    void work();
}

struct ImplemInfo {
    
    
    int weight;
    MyIntf function() instantiate;
}

ImplemInfo[] implems; //实现列表
int totalWeight;

MyIntf chooseImplem() {
    
    
    import std.random;
    auto pick = uniform(0, totalWeight);
    auto slice = implems[];
    assert(slice.length > 0);
    while (slice[0].weight <= pick) {
    
    
        pick -= slice[0].weight;
        slice = slice[1 .. $];
    }
    return slice[0].instantiate();
}
 //使用`CRTP`在`.implems`中`自动注册`实现的`基类`,从而无需`每个子类`中的太多样板.
class Base(C) : MyIntf {
    
    
    //继承类必须定义一个`编译时`可读的`.weight`成员.
    static assert(is(typeof(C.weight) : int),
        "继承类必须定义.weight成员");
    static this() {
    
    
        implems ~= ImplemInfo(C.weight, () {
    
    
            return cast(MyIntf) new C;
        });
        totalWeight += C.weight;
    }
    //继承类必须实现它
    abstract void work();//..
}
//类位置
class Implem1 : Base!Implem1 {
    
    
    enum weight = 1;
    override void work() {
    
     writeln(typeof(this).stringof); }
}
class Implem2 : Base!Implem2 {
    
    
    enum weight = 2;
    override void work() {
    
     writeln(typeof(this).stringof); }
}
class Implem3 : Base!Implem3 {
    
    
    enum weight = 3;
    override void work() {
    
     writeln(typeof(this).stringof); }
}
void main() {
    
    
     //通过`管道`把程序输出传递给`"sort|uniq-c"`来验证是否`正确`生成了`期望分布`.
    foreach (_; 0 .. 100) {
    
    
        auto impl = chooseImplem();
        impl.work();
    }
}

猜你喜欢

转载自blog.csdn.net/fqbqrr/article/details/135377919
d
<d>
d'd