2016-06-29 3 views
7

私はSOLIDの原則を使用してより良いプログラミングの習慣を学ぼうとしています。ここでは、Shapesのサンプルアプリケーションを扱っています。私はちょうど知りたいです、私はどこでも原則を破っています。下はクラスとそのコードです。これは私のSOLID Principleを破っていますか?

1.基本クラス - ベースクラス形状を実現するなど長方形、三角形のような形状に対して

public abstract class Shape 
{ 
    public abstract double Area(); 
    public virtual double Volume() 
    { 
     throw new NotImplementedException("You cannot determine volume from here...Method not implemented."); 
    } 
} 

2クラスの形状を有します。

public class Circle : Shape 
{ 
    public int Radius { get; set; } 
    public override double Area() { return 3.14 * Radius * Radius; } 
} 

public class Triangle : Shape 
{ 
    public int Height { get; set; } 
    public int Base { get; set; } 
    public override double Area() 
    { 
     return 0.5 * Base * Height; 
    } 
} 

public class Rectangle : Shape 
{ 
    public int Length { get; set; } 
    public int Breadth { get; set; } 
    public override double Area() 
    { 
     return Length * Breadth; 
    } 
} 

public class Square : Shape 
{ 
    public Square() { } 
    public int Side { get; set; } 
    public override double Area() 
    { 
     return Side * Side; 
    } 
} 

3. Shapeを返すファクトリクラス。

internal class ShapeFactory<K, T> where T : class, K, new() 
{ 
    static K k; 
    private ShapeFactory() { } 

    public static K Create() 
    { 
     k = new T(); 
     return k; 
    } 
} 

ここティルすべてが罰金だとよさそうだが、私はそれを実装したときに問題が発生します。私はここで少し混乱しています。

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     try 
     { 

      var c = ShapeFactory<Shape, Circle>.Create(); 
      // this part is not clear to me. See the questions below 
      if(c is Circle) 
      { 
       var circle = c as Circle; 
       circle.Radius = 5; 
       Console.WriteLine(string.Format("{0}", circle.Area())); 
      } 


     } 

     catch (Exception ex) 
     { 

      Console.WriteLine("Error: {0}", ex.Message); 
     } 
     Console.Read(); 
    } 
} 

質問

  1. 円は半径を有するように異なる形状が三角形ようにベースと高さを持っていると、異なる特性を持っているので、私は自分の特性を維持することを決定した:最初のフロントエンドのコードを見てみましょう子クラスで。私は基本クラスの仮想メンバーとしてそれを持つことができることを知っていました。だから上にコード化された以外の方法がありますか?

  2. もし私がShapeオブジェクトをサークルオブジェクトに型キャストしているのであれば、抽象クラスの使用は何ですか? Circle c = new Circle()を簡単に使うことができます。私は(cが円であれば)望ましくない小切手を望んでいません。

  3. どうすれば、円の円周率を得るための新しい方法を実装するように求められますか。新しいAbstractクラスを作成するか、Circleクラスに配置する必要がありますか?しかしサークルを入れれば、ソリッドの最初の原則、すなわちSRP を破ると思います。 私の抽象クラスは、不必要または繰り返しのプロパティを持つファットクラスではありません。事前に

おかげ

+5

http://codereview.stackexchange.com/は、あなたの入力のための – Papa

答えて

0
  1. 異なる子クラスは予想して、[OKだと、異なる特性を持つことになります。通常、すべての派生クラスが基本クラスと全く同じプロパティを持つわけではありません。 ShapeRadiusを強制する理由はありません。どのような利点がありますか?それはトラブルのためにドアを開くだけです。この究極の目標は何ですか? myShape.Dimension = valueのようなものを持っていて、それが半径、辺などであれば気にしませんか?あなたのニーズに応じて、何でもできます。あなたの抽象クラスで

  2. あなたは、例えば、Shapeのリストとをループはあなたの結果を得ることを知って、Area()またはVolume()を呼び出すことができます(にもかかわらず、あなたはまだVolumeを実装されていません)。また、基底クラスにはいくつかの共通コードがある可能性があります。このコードでは、使用していません。例えば、Unitプロパティを持つことができます。これはcm、inches、metersなどです。

    public string GetAreaString() 
    { 
        return string.Format("{0} {1}", this.Area().ToString(), this.Unit); 
    } 
    
  3. だけCircleでそれを実装、もちろん:その後、この(愚かな例)のようなメソッドを持っています。なぜそれがCircleの責任を壊すのだろうか?あなたのクラスは、のように、nullの長さかその長さを知らせるように、 の関連値の計算を処理しています。

6

このケースで私が通常行うことは、コンストラクタパラメータを具象クラスに渡すことです。だから私は次のようにあなたの具体的な形状を変更したい:

public class Circle : Shape 
{ 
    public int Radius { get; set; } 

    public Circle(int radius) { 
     this.Radius = radius; 
    } 

    public override double Area() { return 3.14 * this.Radius * this.Radius; } 
} 

public class Rectangle : Shape 
{ 
    public int Length { get; set; } 
    public int Breadth { get; set; } 

    public Rectangle(int lenght, int breadth) { 
     this.Length = lenght; 
     this.Breadth = breadth; 
    } 

    public override double Area() 
    { 
     return Length * Breadth; 
    } 
} 

とファブリックが今のようになりますので、だから今

に、私は、ファクトリメソッドを使用します。

public abstract class ShapeFactory 
{ 
    abstract Create(); 
} 

public class CircleFactory : ShapeFactory 
{ 
    private int radius; 

    public CircleFactory(int radius){ 
     this.radius = radius; 
    } 

    protected override Shape Create() 
    { 
     return new Circle(this.radius); 
    } 
} 

public class RectangleFactory : ShapeFactory 
{ 
    private int length; 
    private int breadth; 

    public RectangleFactory(int length, int breadth){ 
     this.lenght = length; 
     this.breadth = breadth;  
} 

    protected override Shape Create() 
    { 
     return new Rectangle(this.length, this.breadth); 
    } 
} 

今では、独自のコンストラクタで渡されたコンストラクタを使用してシェイプを構築する方法を知っていることに注目してください。

異なる形状を使用するたびに、新しいファクトリをインスタンス化します。

ShapeFactory factory = new CircleFactory(5); 
Shape shape = factory.Create(); 
Console.WriteLine(shape.Area())); 

私はこれがあなたの1番目と2番目の質問に答えると思います。

ので、3:あなたは、あなたのクラスは、このメソッドを実装する方法を実行時に合格するために、戦略パターンを使用している変更いけないために何ができるか :これはあなたのトレーニングに役立ちます

public interface IPerimeter 
{ 
    int calculatePerimeter(); 
} 

public class Circunference : IPerimeter 
{ 
    public int calculatePerimeter(Circle circle) { 
     return 2*pi*circle.radius; 
    } 
} 

public class Circle : Shape 
{ 
    public int Radius { get; set; } 
    private IPerimeter perimeter; 

    public Circle(int radius, IPerimeter perimeter) { 
     this.Radius = radius; 
     this.perimeter = perimeter; 
    } 

    public Circunference() { 
     perimeter.calculatePerimeter(this); 
    } 

    public override double Area() { return 3.14 * this.Radius * this.Radius; } 
} 

希望。

+0

おかげで、この質問に適しだろう。本当にそれを感謝します。それでもなお、ShapeFactoryクラスの使用と本体は何ですか?あなたはその答えに言及していません。ジェネリッククラスを使用していますか、それともあなた自身のものです。私は具体的なクラスとしてCircleFactoryとRectangleFactoryを見ることができます。 –

+0

ああ、私はこのクラスを忘れてしまった... このクラスは単純な抽象メソッドを持つ抽象クラスです。Create().. updated above – guijob

+0

あなたのコードにはいくつかの誤りがあると思います。例えば、私はあなたが意味するものだと思う '公共のint Circunference()'(それ以外の場合は、コンストラクタのように見える)、私はあなたがその計算return' 'にそれをしたいと思います。 ';また' IPerimeter'の方法は、int型のcalculatePerimeter(サークル円) 'でなければなりません。最後に、このメソッドは 'return(int)(2 * Math.PI * circle.Radius);'でなければなりません。ところで、いくつかの 'lenght'もあります。 ;) – Andrew

0

あなたの例は、実際には設計されているようです。私はあなたが何よりも何も働かない最もシンプルなものを常に実装すべきだと思います。私はこれがコードの例であることを知っています。なぜなら、あなたはソリッドな原則を学びたいからです。しかし、間違った文脈でこれらの原則がどれほど間違っているかを知ることは重要です。あなたの特定のコードでは、シェイプクラスを使ってすべてのシェイプをグループ化する必要がありますか?つまり、シェイプのリストを繰り返し処理し、面積と体積を計算することを計画していますか?もしそうでなければ、継承は全く意味を持ちません。実際には、私は、継承は最近、過度に使用されていると言っています。過度に使用されると、醜い継承依存グラフになります。工場クラスについて:あなたの「形状」オブジェクトの構築は特に難しく、時間がかかり、扱いにくいですか?あなたの工場クラスはいくつかの価値を提供していますか、それとも完全に役に立たないのですか?存在する本当の理由がない場合は、私はそれを使用しません、新しい演算子ははるかに明確です。

あなたの返信に気にしないことを願っていますが、いくつかの固い原理が非常に特定のシナリオに当てはまるという事実を知りたがっています。それらを間違った場所に強制すると、醜く複雑なコードが発生する可能性があります。実際の状況では、上記の質問に「はい」と答えると、あなたのパターンはOKと思われます。さもなければ、まったく同じパターンは本当のメリットがなくても事を複雑にする可能性があります。私のポイントは次のようなものだと思います。あらゆるソリッドの原則がどんな状況でも良いわけではありません。

0

これは非常に一般的な問題です。 SOLIDの学習は素晴らしいですが、抽象化や間接化などの基本的な設計原則を理解する必要があります。あなたが混乱している理由は、コードに抽象化がないからです。

あなたは、図形の面積を知りたいコードを持っている想像し、それはそれが何であるか形状を気にしないでもその形の面積を計算する方法。次のようなものがあります。

public void PrintArea(Shape shape) 
{ 
    Console.WriteLine(shape.Area()); 
} 

これはOOPデザインの重要な部分です。あなたの例には絶対に何もありません。あなたの例では、ただ不自然なことに何のロジックを持っていないコードの一部、ましてやSOLIDされています。

関連する問題