应用战略模式

时间:2014-06-03 22:14:09

标签: vba design-patterns modeling strategy-pattern

想象一下,你有一个工厂,通过皮带将产品带到制造过程中。在其中的某个地方,有必要根据一些商业逻辑将产品流从单个皮带输入分割到多个皮带上。也许它们需要用红色,绿色和蓝色产品的输出带分开。也许它是某种简单的负载平衡,所以产品需要根据每个输出带的百分比进行拆分。

                  ________________
                 / ___Color=Red___...
    ____________/ /_______________
 ..._Products___  ____Color=Green_...
                \ \_______________
                 \____Color=Blue__...

或者

                  __________
                 / ___60%___...
    ____________/ /_________
 ..._Products___  ____20%___...
                \ \_________
                 \____20%___...

具体而言,我试图对routing functionality of ProModel进行逆向工程。路由方法应该能够在运行时进行更改,就像各个输出带的路由属性一样。 (比如改变颜色标准)。如果路由方法切换回先前定义的路由方法,则会记住所使用的设置。

为了保持我的代码概括,产品是"实体"物体,分开的带是"路线"对象,内部路由逻辑是" RoutingRule"整个输入带/内部逻辑/输出带的东西是一个" Router"。基于ProModel的使用," RoutingRule"适用于"路由器"而不是个人"路线" - 如果规则是 RouteByPercent ,则每个传出"路由"应该有一个百分比,而如果它是 RouteByAttribute ,每个"路由"将有一个属性/比较者/标准(例如"颜色"," =","蓝")设置为测试来自"实体&#34 ;

我可以看到使用策略模式可以灵活地支持和交换" RoutingRule"对象(例如ProModel链接中可能的规则列表);但是,我不太清楚如何在没有紧密耦合" RoutingRule"的情况下存储每个规则的状态信息。和#34;路线"对象。

将战略模式应用于此案例时,我应该如何存储每个路由适用的特定于路由规则的属性?我试图通过我的选项进行思考而我不会像其中任何一个一样:

  1. 天真的方法是在Route类中为所有可能的RoutingRules提供成员变量:m_Percentm_EntityAttribute / m_EntityComparator / m_EntityCriteria ...但那样会因为明显的原因而变得可怕。每当我添加一种新的RoutingRule时,我都必须将成员变量添加到Route类。
  2. 我计划这样做的方式是使用关联数组(Dictionary或自定义HashTable),因此可以动态添加或删除属性。这通常很好,但必须有一些代码来a)初始化特定于规则的属性b)告诉我需要为当前规则设置哪些属性(我不能只提示用户所有路由属性,因为它们可能并非全部由当前选定的规则使用)c)验证Route属性是否处于一致状态。
  3. 我能想到的另一种方法是将Route属性存储在RoutingRule本身内,这是一个关联数组内的关联数组,因此我可以按名称查找Route并获取每个应用的确切属性列表当前规则的路线。这种方式解耦最多,但后来我不确定如何构造它,以便向Route询问其属性是一个透明的过程。而不是像#1和#2这样的Route.Attributes(strAttrName),它更像是RoutingRule.RouteAttributes(Route.Name).Attributes(strAttrName)
  4. 也许我过度思考这个?
  5. 顺便说一下,我在VBA中执行此操作时会考虑所有限制。

1 个答案:

答案 0 :(得分:1)

检查用某种语言编写的骨架:

class Entity { // Or call this the EntityHolder
  Map attrs;
  RealEntity re; // The payload
}

abstract class RouteElement {
  void process(Entity entity);
  Map attrs;
}

interface RouterRule {
  RouteElement pickNextRouteElement(Entity e, List<RouteElement> allOutRoutes);
}

class Router extends RouteElement {
  List<RouteElement> outRoutes;
  RouteElement deadRoute;
  RouterRule routerRule;

  void process(Entity entity) {
    RouteElement nextRouteElement = routerRule.pickNextRouteElement(entity, outRoutes);

    if (nextRouteElement == null) {
      if (deadRoute) {
        deadRoute.process(entity);
      }
    } else {
      nextRouteElement.process(entity);
    }
  }

  void setRouterRule(RouterRule rr) {
    routerRule = rr;
  }

  RouterRule getRouterRule() {
    return routerRule;
  }

  void addOutRouteElement(RouteElement re) {
    outRoutes.add(re);
  }

  void setDeadRoute(RouteElement re) {
    deadRoute = re;
  }
}

class ColorRouterRule implements RouterRule {

  RouteElement pickNextRouteElement(Entity e, List<RouteElement> allOutRoutes) {
    foreach(RouteElement re in allOutRoutes) {
      if (e.getAttr("color") == re.getAttr("color") {
    return re;
      }
    }

    return null;
  }
}

class RandomRouterRule implements RouterRule {

  RouteElement pickNextRouteElement(Entity e, List<RouteElement> allOutRoutes) {
    int rand = random(0, allOutRoutes.length());
    return allOutRoutes.get(rand);
  }
}

class PercentRouterRule implements RouterRule {
  RouteElement pickNextRouteElement(Entity e, List<RouteElement> allOutRoutes) {
    int[] weights = int[allOutRoutes.length()];

    int prevWeight = 0;
    for (i = 0; i < weights, i++) {
      weights[i] = prevWeight + allOutRoutes.get(i).getAttr("percent");
      prevWeight = weights[i];
    }

    int rand = random(0, prevWeight);

    for (i = 0; i < weights, i++) {
      if (rand <= weights[i]) {
        return allOutRoutes[i];
      }
    }
  }
}

class RouterManager {

  Router routerBeingManaged;
  Stack<RouterRule> oldRouterRules;

  void setNewRouterRule(RouterRule rr) {
    oldRouterRules.push(routerBeingManaged.getRouterRule());
    routerBeingManaged.setRouterRule(rr);
  }

  void revertToOldRouterRule() {
    routerBeingManaged.setRouterRule(ooldRouterRules.pop());
  }

  ..
}


class Route extends RouteElement {
  List<RouteElement> route;

  void addRouteElement(..) {
    ..
  }

  void process(Entity entity) {
    foreach(RouteElement as re in route) {
      re.process(entity);
    }
  }
}

class MyApp {

  void main() {
    Route r = new Route();

    // Build the route
    r.addRouteElement(...);
    r.addRouteElement(...);

    Router router1 = new Router();
    router1.addOutRouteElement(..);
    router1.addOutRouteElement(..);
    router1.addOutRouteElement(..);

    RouterManager router1Mgr = new RouterManager(router1);
    router1Mgr.setRouterRule(new RandomRouterRule());

    r.addRouteElement(router1);

    r.addRouteElement(...);
    r.addRouteElement(...);

    // Get entities from somewhere
    r.process(entity);

    // Change the router rule
    router1Mgr.setRouterRule(new PercentRouterRule());

    // Get entities from somewhere
    r.process(entity);

    // Revert the router rule
    router1Mgr.revertToOldRouterRule();

    // Get entities from somewhere
    r.process(entity);
  }
}