为什么这种类型的代码被认为是良好的编程实践以及为什么有些代码被认为是错误的?

时间:2017-06-09 13:28:29

标签: java dependency-injection

在常见的编程结构中,我已经看到了例如。

class Showframe
{
   psvm(String args[])
   {
      Artframe artframe = new Artframe(new Drawing());
      //some commands
   }
}

class Artframe extends JFrame
{ 
   Drawing drawing;
   public Artframe(Drawing drawing)
   { this.drawing = drawing; }
   //some commands
}

class Drawing
{
   //some things over here
}

我想知道为什么这样做? 为什么不

与上面相同的绘图类

在ShowFrame中

代替:Artframe artframe = new Artframe(new Drawing());

我们写道:

  

Artframe artframe = new Artframe();

并将Artframe类的构造函数更改为:

  

drawing = new Drawing();

我的意思是为什么我们不这样做?这有什么问题,为什么它被认为是糟糕的编程习惯?

2 个答案:

答案 0 :(得分:1)

让我们对您的Artframe课程进行单独审核:

public Artframe(Drawing drawing)
{ this.drawing = drawing; }

public Artframe()
{ this.drawing = new Drawing(); }

实际上有不同的语义。

第一个创建一个新的artframe,其中包含您将从客户端传递的任何现有绘图。第二个创建一个新的artframe,它有一个新的(空?)绘图。

第二个不一定(但仍然可能)是糟糕的设计,如果这些语义是你的要求并且适合更大的画面"。

在大多数情况下,第一个是更好的设计,原因有几个(我会猜测你的整体架构):

  • 职责分离/单一责任/高凝聚力 Artframe班级职位是框架Drawing。这应该是它唯一的工作。决定绘制框架的内容已经是第二份工作。
  • 可重复使用性:您无法将框架与现有图纸一起使用。
  • 松散耦合:您可以使用界面进行规范设计。这使您可以轻松使用不同的实现。第二个版本是硬连线("耦合")到特定实现。

答案 1 :(得分:0)

假设您要创建一个简单的类,用任何名称打印问候语:

public class Greeting {

    private final String name;

    public Greetings(String name) {
        this.name = name;
    }

    public void printHello() {
        System.out.println("Hello " + name + "!");
    }
}

当您通过String s = "World"时,结果将为"Hello World!"。这样,您就可以更改Greeting类的行为。如果Greeting类看起来像这样:

public class Greeting {
    public void printHello() {
        System.out.println("Hello java!");
    }
}

没有任何选项可以更改此问候语。

同样适用于课程ArtframeDrawingArtframe只显示您提供的内容。 注意,以下代码片段无法编译,因为它们使用不存在的图形上下文,方法,...

interface Drawing {
    void paintTo(Canvas c);
}

class Artframe extends JFrame {
    Drawing drawing;

    public Artframe(Drawing drawing) {
       this.drawing = drawing;
    }

    protected void paint(Canvas c) {
        drawing.paintTo(c);
    }
}

绘图可以通过各种方式实现e。 G。一个实现绘制到图形上下文圆,其他绘制矩形,....

public CircleDrawing implements Drawing {
    Point centerPoint = new Point(0,0);
    int radius = 5;
    int strokeWidth = 1;

    public void paintTo(Canvas c) {
        c.drawCircle(centerPoint, radius, strokeWidth);
    }
}

public RectangleDrawing implements Drawing {
    Point topLeft = new Point(0,0);
    Dimension dim = new Dimension(100, 50);
    int strokeWidth = 1;

    public void paintTo(Canvas c) {
        c.drawRect(topLeft , dim, strokeWidth);
    }
}

要在Artframe中显示圈子,您只需要传递CircleDrawing实例:

new Artframe(new CircleDrawing());

如果需要显示矩形,则:

new Artframe(new RectangleDrawing());

同样,如果你的Artframe课程没有Drawing依赖关系,我。即使用过的图形会被硬编码到Artframe中,然后您将无法更改它的行为 - 显示的内容始终相同Drawing

class Artframe extends JFrame {
    Drawing drawing = new RectangleDrawing();

    protected void paint(Canvas c) {
        drawing.paintTo(c);
    }
}