JAVA:选择基于多维的算法

时间:2015-04-01 13:11:02

标签: java design-patterns

我有一个类地址的实例,我必须根据环境改变:
1)Region:具有子类RegionA和RegionB的基类 2)站点:具有子类SiteA,SiteB和SiteC的基类 3)语言:具有子类LanguageA和LanguageB的基类 每个子类定义有关地址修改的约束 问题是每个元组(Region,Site,Language)都必须定义自己的修饰符。

所以,我有一个方法adjust(地址a,地区r,网站s,语言l):

void adjust(Address a, Region r, Site s, Language l){  
    if(r instanceof Russia && s instanceof MailRu && Language instanceof Russian){
        a.set_street("abc")
    }
    else if(r instanceof Russia && s instanceof MailRu && Language instanceof English){
        a.set_street("fgh")
    }
}

在这种情况下使用的最佳设计模式是什么?

2 个答案:

答案 0 :(得分:2)


RegionLanguage是(子)产品(分别是他们的工厂,当你考虑我的方式时),用于在Address中创建街道。

package address.example;

public class AddressExample
{
  public static void main(String[] args)
  {
    LanguageFactoryProvider lfp = new LanguageFactoryProvider.LanguageFactoryProviderImpl();
    RegionFactoryProvider rfp = new RegionFactoryProvider.RegionFactoryProviderImpl();
    AddressProvider provider = new AddressProvider(lfp, rfp);

    Address a = provider.createAddress("RU", "USA", "Famous Street");
    System.out.println(a.getStreet());

    System.out.println("-----");

    Address b = provider.createAddress("EN", "RUS", "Good Street");
    System.out.println(b.getStreet());
  }
}

输出

Address format: RU
Famous Street
USA
-----
Address format: EN
Good Street
RUS

这是地址类,你可以看到它将街道创建的部分内容委托给regionlanguage(这没什么特别的,但你明白了。)

package address.example;

import address.example.LanguageFactoryProvider.Language;
import address.example.RegionFactoryProvider.Region;

public interface Address
{
  public String getStreet();

  static class AddressImpl implements Address
  {
    private final Region region;
    private final Language language;

    private final String street;

    public AddressImpl(Region region, Language language, String street)
    {
      this.region = region;
      this.language = language;
      this.street = street;
    }

    @Override
    public String getStreet()
    {
      StringBuilder sb = new StringBuilder();
      sb.append(String.format("Address format: %s", language.getSpecifier()));
      sb.append(String.format("%n"));
      sb.append(street);
      sb.append(String.format("%n"));
      sb.append(region.getSpecifier());
      return sb.toString();
    }
  }
}

这是其他使用的类。我会再次添加一些想法。

package address.example;

import address.example.LanguageFactoryProvider.Language;
import address.example.RegionFactoryProvider.Region;

public class AddressProvider
{
  private final LanguageFactoryProvider lfp;
  private final RegionFactoryProvider rfp;

  public AddressProvider(LanguageFactoryProvider lfp, RegionFactoryProvider rfp)
  {
    this.lfp = lfp;
    this.rfp = rfp;
  }

  public Address createAddress(String language, String region, String street)
  {
    Language _language = lfp.getLanguageFactory(language).createLanguage();
    Region _region = rfp.getRegionFactory(region).createRegion();
    return new Address.AddressImpl(_region, _language, street);
  }
}

package address.example;

import java.util.HashMap;
import java.util.Map;

public interface LanguageFactoryProvider
{
  public LanguageFactory getLanguageFactory(String language);

  static interface LanguageFactory
  {
    public Language createLanguage();
  }

  static interface Language
  {
    public String getSpecifier();
  }

  static class LanguageImpl implements Language
  {
    private final String specifier;

    public LanguageImpl(String specifier)
    {
      this.specifier = specifier;
    }

    @Override
    public String getSpecifier()
    {
      return specifier;
    }
  }

  static class LanguageFactoryProviderImpl implements LanguageFactoryProvider
  {
    private static final Map<String, LanguageFactory> factories = new HashMap<>();
    static
    {
      factories.put("EN", new EnglishLanguageFactory());
      factories.put("RU", new RussianLanguageFactory());
    }

    @Override
    public LanguageFactory getLanguageFactory(String language)
    {
      if (!factories.containsKey(language))
        throw new IllegalArgumentException();

      LanguageFactory factory = factories.get(language);
      return factory;
    }
  }

  static class RussianLanguageFactory implements LanguageFactory
  {
    @Override
    public Language createLanguage()
    {
      return new LanguageImpl("RU");
    }
  }

  static class EnglishLanguageFactory implements LanguageFactory
  {
    @Override
    public Language createLanguage()
    {
      return new LanguageImpl("EN");
    }
  }
}

package address.example;

import java.util.HashMap;
import java.util.Map;

public interface RegionFactoryProvider
{
  public RegionFactory getRegionFactory(String region);

  static interface RegionFactory
  {
    public Region createRegion();
  }

  static interface Region
  {
    public String getSpecifier();
  }

  static class RegionImpl implements Region
  {
    private final String specifier;

    public RegionImpl(String specifier)
    {
      this.specifier = specifier;
    }

    @Override
    public String getSpecifier()
    {
      return specifier;
    }
  }

  static class RegionFactoryProviderImpl implements RegionFactoryProvider
  {
    private static final Map<String, RegionFactory> factories = new HashMap<>();
    static
    {
      factories.put("RUS", new RussianRegionFactory());
      factories.put("USA", new UsRegionFactory());
    }

    @Override
    public RegionFactory getRegionFactory(String region)
    {
      if (!factories.containsKey(region))
        throw new IllegalArgumentException();

      RegionFactory factory = factories.get(region);
      return factory;
    }
  }

  static class RussianRegionFactory implements RegionFactory
  {
    @Override
    public Region createRegion()
    {
      return new RegionImpl("RUS");
    }
  }

  static class UsRegionFactory implements RegionFactory
  {
    @Override
    public Region createRegion()
    {
      return new RegionImpl("USA");
    }
  }
}

答案 1 :(得分:1)

这是具有许多案例/规则的典型业务“逻辑”。为此制定声明性解决方案是值得的。

<rule>
    <when category="Region" value="Russia"/>
    <when category="Site" value="MailRu"/>
    <action category="Address" value="abc"/>
</rule>

这允许构建诊断,完整性检查,记录未发现的案例,制作历史日志,以便将来对错误报告进行分析。

它甚至可能更具可读性。可以在一个漂亮的HTML表层次结构中转换为管理器级文档。


归结为您的代码是程序性的,无法存储所采用的控制流路径。模型驱动的方法可以缓解这种情况。 DSL是可行的,但我发现自由形式数据方法更有创意,更直接。