2009-05-31 9 views
3

このデザインをどのようにリファクタリングする必要がありますか?このデザインをリファクタリングする方法

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 * Seasonal rateで、サービスごとに異なります。

私はサービスクラスまたは派生クラスのいずれかに料金を保存したくありません。 SeasonalRateを返す各ServiceTypeのメソッドを持つSeasonalRateプロバイダを作成することをお勧めしますか?
問題は、季節的な料金が変更され、頻繁に変更される可能性があることです。サービスクラスを変更することには注意が必要です。また、SeasonalRatesクラスのサービスクラスに対するメンテナンス可能な依存関係を維持したいと考えています。
ServiceClass(ビジターの一種)ごとにSeasonalRatesクラスをオーバーロードして実装することをお勧めしますか?すべてのSeasonalRatesクラスですべてのServiceTypeのメソッドを実装する必要がありますか?
SeasonalRateクラスは、DiscountRate、ZipCodeRateなどの料金を計算する他のクラスも存在するため、どのインターフェースを実装する必要がありますか?
さらにServiceTypeクラスが追加されると、すべての訪問者に変更を維持することは難しいでしょうか?

編集:すべての料金はサービスタイプによって異なります。例えば、昼と夜のサービスのためのSeasonalRatesは次のように標準のVisitorパターンを使用して上ジェフミートボールヤンによって提案されたアプローチの長所/短所だろう何異なる

あり、以下:

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

それはあなたのようです戦略パターンを探しています:何かを計算するいくつかの方法?共通のインタフェースを使用し、具体的なオブジェクトに異なる動作を実装するだけです。これは興味深い問題である

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 { } 
+0

こんにちは。 ansのThx。問題は、すべてのRateStrategiesが同じではないということです。例えば、ZipCodeRateはnullを返すことはありません。同様に、製品サムネイルなどを取得するなど、他の操作も追加する必要があります。これには、さまざまなStrategy基本タイプとServiceオブジェクトの頻繁な変更が必要です。 –

+0

RatedServiceから継承したオブジェクトの変更を意味しますか? サービスの種類によって使用される戦略を変更するたびに、継承したクラスのいくつかの行を変更する必要があります。あなたがDayServiceを割引すれば、そのクラスで何かを変更する必要があります。 私がここに提案しているのは、変更することです: DayService(){super(new DefaultStrategy();} to: DayService(){super(new Discount(0.8));} 非常に小さい変更の量... – NicDumZ

+1

+1:私はこのアプリでこのようなことをしますが、税計算のために:アプリケーションが機能している地域に応じてdif戦略メソッドがあります。 –

0

:何について

。私はこのデザインの目標を反映したいので、間違っていれば修正することができます。

あなたの説明から、サービスは複数の料金を持つことができるようです。サービスインスタンスは、1つに関する以下の場合の(またはそれ以上):

SeasonalRate、DiscountRate、 ZipCodeRateなど

Iはまた、ビジターオブジェクトのようなものがあることが集まります

DayService、NightService、 TwentyFourServiceなど

0:、それは1つ以上のサービスに関連します

ここでの作業は、実行されているサービスのプロパティと適用される料金に応じてビジターに正しく請求することです。あなたが必要なインターフェースを理解すべき関係を可視化

。すべてのレートですべてのサービスが呼び出せるインターフェースを実装する必要があるようです。

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

これにより、Rateを使用して、サービスに基づいて戻り値を決定することができます。すべてのサービスがすべてのRateオブジェクトに決定を下すために必要なすべてのデータを利用できるように、インタフェース(IChargeable、IExtendableなど)を実装することが重要です。

は、ここで私は考えています何の例です:

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; 
    } 
} 

これはあなたの料金のオブジェクトは、必要に応じて変更することができますが、あなたのビジネスの変数がかなり明確に定義されなければならないため、各サービスに必要な変更を低減し、サービス基本クラスでは比較的変化しません。例えば

、あなたのNightServiceは、サムネイルを持っていない可能性があり、そしてそれは、明示的GetThumbnail機能を実装する必要はありません。単にServiceのデフォルトの実装を継承します。

+0

こんにちは、レートは単なる例です。このようNWのプロパティが導入されている場合は、我々が最初に訪問した理由、サービスクラスは。厥を変更する必要がありますサービスの説明、サムネイル、などのような他の特性もあります。 –

+0

また、季節の料金はサービスによって異なります。 –

+0

ありますServiceクラスの新しいプロパティ(インターフェイス)を追加して実装することは害ではない他のすべてのサービスが派生するベースクラス(抽象クラ​​ス)。各プロパティは、サービスをパラメータとして取るインタフェースを実装します。私の編集を参照してください。 –

関連する問題