我应该如何重构这个设计

时间:2009-05-31 06:21:10

标签: design-patterns oop interface

我应该如何重构这个设计?

class Service : IChargeable, IExtendable<br />
{

}

interface IChargeable
{
decimal? ChargeableAmount { 
    get; 
    }
}

interface IExtendable
{
bool IsExtendable { 
    get; 
    }
}

class DayService : Service { } 
class NightService : Service { } 
class TwentFourService : Service { }

问题是这些服务是按不同的费率收取的,具体取决于它们是可扩展的还是取决于它们的类型 如果服务延长,则收取一定比例的应课税金额。服务费是ChargeableAmount *季节性费率,每项服务都有所不同。

我不想将费率存储在服务类或任何派生类中。创建一个SeasonalRate提供程序是不是一个好主意,该提供程序为每个返回SeasonalRate的ServiceType提供方法?
问题是季节性费率可能会发生变化并且经常发生变化,我们对更改服务类更加谨慎。我们还希望在SeasonalRates类中对Service Classes具有可维护的依赖性。
为每个ServiceClass(一种访问者)实现具有重载的SeasonalRates类是一个好主意吗?所有SeasonalRates类都必须实现所有ServiceTypes的方法,这是一个问题吗?
SeasonalRate类应该实现什么接口,因为还有其他类可以计算诸如DiscountRate,ZipCodeRate等的费率?
如果添加了更多的ServiceType类,是否难以维护所有访问者的更改?

编辑:所有费率因ServiceType而异。例如,DayalRates for Day and Night Services是不同的

Jeff Meatball Yang建议使用标准访客模式的方法有哪些优点/缺点:

interface IVisitable
{
    Accept(IVisitor visitor);
}
interface IVisitor
{
    Visit(IVisitable visitable);
}
interface IRate
{
    Rate { get; }
}

class Service : IVisitable
{
    public virtual Accept(IVisitor visitor);
}
class Visitor : IVisitor
{
    public virtual Visit(IVisitable visitable) { }
    public virtual Visit(DayService visitable) { }
    public virtual Visit(NightService visitable) { }
}
class RateVisitor : Visitor, IRateVisitor
{
    decimal? _Rate;

    override Visit(IVisitable visitable) { };
    override Visit(DayService visitable) { // Logic Goes here, sets the _Rate Variable };
    // Overrides for other services

    public virtual Rate 
    {
        return this._Rate;
    }
} 

2 个答案:

答案 0 :(得分:2)

看来你正在寻找策略模式:几种计算方法?只需使用通用接口,并在具体对象中实现不同的行为。

怎么样:

class Service : IChargeable, IExtendable
{

}

interface IChargeable {  
    decimal? ChargeableAmount { get; }  
}

interface IExtendable {  
    bool IsExtendable { get; }  
}

class RatedService: Service {  
    RateStrategy strategy;  
}

interface RateStrategy {  
    decimal SeasonalRate { get; }  
}

class DiscountRate: RateStrategy {}  
class ZipCodeRate: RateStrategy {}  

class DayService : RatedService { }  
class NightService : RatedService { }  
class TwentFourService : RatedService { }

答案 1 :(得分:0)

这是一个有趣的问题。我想反思这个设计的目标,所以如果我弄错的话,你可以纠正我。

根据您的描述,似乎服务可以有多种费率。服务实例与以下实例中的一个(或多个)相关:

  

SeasonalRate,DiscountRate,   ZipCodeRate等

我还认为有一个访客对象,它与一个或多个服务有关:

  

DayService,NightService,   TwentyFourService等

我认为此处的任务是根据正在执行的服务的属性以及适用的费率正确向访问者收费吗?

可视化关系应该有助于您了解必要的接口。似乎所有费率必须实现所有服务可以调用的接口。

public interface IRate { 
  decimal GetRate(Service s);
}

这允许费率根据服务决定返回值应该是多少。现在,所有服务都必须实现接口(IChargeable,IExtendable等),以便做出决策所需的所有数据都可用于每个Rate对象。

以下是我在想的一个例子:

public interface IThumbnail {
  string ThumbnailFile { get; }
  int ThumbnailSize { get; }
  Image GetThumbnail();
}
public interface IThumbnailProvider { 
  Image GetThumbnail(Service s);
}

public class Thumbnail : IThumbnailProvider { 
    public Image GetThumbnail(Service s) { 
       if(s.ThumbnailFile != null) {
           // get the image
       }
    }
}

public interface ISeasonal {
  SeasonType Season { get; }
}

public class SeasonalRate : IRate {
  public decimal GetRate(Service s) { 
    if(s.Season != SeasonType.None) {
       // return seasonal rate based on s.Season
    } else {
       // throw an exception or do something else
    }
}

public abstract class Service : IChargeable, IExtendable, ISeasonal, IThumbnail { 
  // default implementation for ISeasonal
  protected SeasonType _season = SeasonType.None;
  public SeasonType Season { get { return _season; } }


  // default implementation for IThumbnail
  protected string _thumbFile = null;
  protected int _thumbSize = 32;
  public string ThumbnailFile { get { return _thumbFile; } }
  public int ThumbnailSize { get { return _thumbnailSize; } }
  public Image GetThumbnail() {
     return null; // 
  } 
}

public class DayService : Service { 
  private IRate _confirmedRate;
  private IThumbnailProvider _fileServer;
  public decimal GetRate() { return confirmedRate.GetRate(this); }
  public Image GetThumbnail() { return fileServer.GetThumbnail(); }

  // constructor
  public DayService(IThumbnailProvider fileServer, IRate confirmedRate) { 
        this._season = SeasonType.Day; 
        this._filename = "sunny.jpg"; 
        this._fileServer = fileServer;
        this._confirmedRate = confirmedRate;
  }
} 

这使您的Rate对象可以根据您的需要进行更改,但会减少每个Service所需的更改,因为您的业务变量应该定义得非常好,并且在Service基类中相对不变。

例如,您的NightService可能没有缩略图,因此不需要显式实现GetThumbnail函数。它只是继承了Service上的默认实现。