如何將過程程式碼變成物件導向的程式碼? - WLODEK
乾淨clean程式碼並不總是物件導向的。有時它將以程式樣式編寫。哪種風格更好:過程式還是物件導向?我們應該在一定條件下進行選擇,以使其易於開發和可讀,根據“Clean守則”的原則。
下面是過程程式碼的示例,它將幫助我考慮程式碼的純度及其對物件導向程式碼的重構。
public class Rectangle { double width; double height; } ... public class Geometry { double area(Object shape) { if (shape instanceof Circle) { Circle circle = (Circle) shape; return Math.PI * circle.radius * circle.radius } else if (shape instanceof Rectangle) { Rectangle rectangle = (Rectangle) shape; return rectangle.width * rectangle.height; } else if (shape instanceof Square) { Square square = (Square) shape; return square.size * square.size; } throw new IllegalArgumentException("Unknown shape"); } } |
如果我主要新增對已經存在的資料結構進行操作的新函式,那麼上述程式碼仍然還是清晰易讀。新函式是返回包含給定圖形的最小矩形。
public class Geometry { Rectange containingRectange(Object shape) { if (shape instanceof Circle) { Circle circle = (Circle) shape; Rectangle rectangle = new Rectangle(); rectangle.width = 2 * circle.radius; rectangle.height= 2 * circle.radius; return rectangle; } else if (shape instanceof Rectangle) { return (Rectangle) shape; } else if (shape instanceof Square) { ... } throw new IllegalArgumentException("Unknown shape"); } } |
但是,如果您計劃新增或修改現有資料結構,則將強制更改所有現有過程性程式碼。當我決定將Rectangle資料結構中的元件更改為描述正方形2個相對角的點時會發生什麼?
public class Point { double x,y; } public class Rectangle { Point topLeft; Point bottomRight; } |
不難看出,這樣的改變將迫使對現有程式進行許多改變。避免許多更改(或將其最小化)的一種方法是將getX()和getY()方法放置在Rectangle結構中,該結構將執行必要的計算。
public class Rectangle { private Point topLeft; private Point bottomRight; double getX(){ return Math.abs(topLeft.x = bottomRight.x); } double getY(){ return Math.abs(topLeft.y = bottomRight.y); } } |
但是請注意,從那一刻起,我開始隱藏資料結構的細節。Rectangle類中的詳細資訊已隱藏,新方法將計算必要的輸出。透過這種方式,我開始將程式碼樣式從過程更改為物件導向。
如何將過程程式碼重構為物件導向的程式碼?
1. |
public class Circle { private final double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } } |
2.為現有資料結構定義一個公共介面/基類,接下來,我定義一個空的“ Shape”基類,它將擴充套件所有資料結構。從現在開始,“area區域”計算過程僅接受“Shape”抽象類擴充套件作為引數。或者,它也可以是一個通用介面。
public abstract class Shape{ } public class Circle extends Shape { private final double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } } |
3.將邏輯從過程程式碼移至基類中,為了將邏輯傳遞給基類,我將做一些小的修改以能夠使用IntelliJ工具中的方法傳遞。
public class Geometry { static double area(Shape shape) { return new Geometry().calculateArea(shape); } private double calculateArea(Shape shape) { if (shape instanceof Circle) { Circle circle = (Circle) shape; return Math.PI * circle.getRadius() * circle.getRadius(); } else if (shape instanceof Rectangle) { Rectangle rectangle = (Rectangle) shape; return rectangle.getWidth() * rectangle.getHeight(); } else if (shape instanceof Square) { Square square = (Square) shape; return square.getSize() * square.getSize(); } throw new IllegalArgumentException("Unknown shape :" + shape.getClass()); } } |
透過提取一個新方法“ calculateArea”:計算區域的邏輯。
然後,將包含“ calculateArea”邏輯的方法從“ Geometry”移到“ Shape”基類。
public class Geometry { static double area(Shape shape) { return shape.calculateArea(); } } public abstract class Shape { double calculateArea() { if (this instanceof Circle) { Circle circle = (Circle) this; return Math.PI * circle.getRadius() * circle.getRadius(); } else if (this instanceof Rectangle) { Rectangle rectangle = (Rectangle) this; return rectangle.getWidth() * rectangle.getHeight(); } else if (this instanceof Square) { Square square = (Square) this; return square.getSize() * square.getSize(); } throw new IllegalArgumentException("Unknown shape :" + getClass()); } } |
這裡有一種程式碼壞味道:“基類取決於其派生類”。解決問題將使我們進入下一個轉變。使用下推方法,在IDE中選擇重構中的Push Members Down。
4.刪除派生類中不必要的邏輯,最後,我們完成了“用多型替換條件表示式”的轉換。在每個子類(即我們的舊資料結構)中,只有一個條件為真。
重構後的結果程式碼:
public class Circle extends Shape { private final double radius; public Circle(double radius) { this.radius = radius; } @Override double calculateArea() { return Math.PI * circle.radius * circle.radius; } } public class Geometry { static double area(Shape shape) { return shape.calculateArea(); } } |
另外,我們可以內聯“ Geometry.area”函式,然後將“ calculateArea”的名稱更改為“ area”,因此我們回到原來的命名。
相關文章
- 如何寫工程程式碼——重新認識物件導向物件
- 物件導向變成 VS 函數語言程式設計物件函數程式設計
- 程式碼壞味道之濫用物件導向物件
- Python物件導向之十二:程式碼測試Python物件
- 物件導向和麵向過程物件
- 如何使用Go語言寫出物件導向風格的程式碼Go物件
- 物件導向與程式導向物件
- 程式導向與物件導向物件
- 物件導向設計介紹和程式碼示例物件
- 物件導向和麵向過程的區別物件
- php中的程式導向與物件導向PHP物件
- Python之物件導向和麵向過程Python物件
- python物件導向(二)繼承:最直接的程式碼複用Python物件繼承
- python-程式導向、物件導向、類Python物件
- 程式碼提交過程
- 解釋下什麼是物件導向?物件導向和麵向過程的區別?物件
- 氣泡排序的演變過程及程式碼演示排序
- 物件導向程式設計物件程式設計
- 心得 : 物件導向和麵向過程的區別【分享】物件
- 20200820 - 程式導向和麵向物件物件
- 《神經網路的梯度推導與程式碼驗證》之CNN前向和反向傳播過程的程式碼驗證神經網路梯度CNN反向傳播
- javascript:物件導向的程式設計JavaScript物件程式設計
- JS物件導向的程式設計JS物件程式設計
- Scala的物件導向程式設計物件程式設計
- python物件導向入門(1):從程式碼複用開始Python物件
- Python物件導向多型實現原理及程式碼例項Python物件多型
- 《神經網路的梯度推導與程式碼驗證》之FNN(DNN)前向和反向傳播過程的程式碼驗證神經網路梯度DNN反向傳播
- 理解了物件導向,我突破了地元境,程式碼寫的真棒!物件
- Python物件導向程式設計Python物件程式設計
- 程式設計思想 物件導向程式設計物件
- js物件導向程式設計JS物件程式設計
- 十三、物件導向程式設計物件程式設計
- 十六、物件導向程式設計物件程式設計
- Python 物件導向程式設計Python物件程式設計
- JS物件導向程式設計(一):物件JS物件程式設計
- 程式導向和麵向物件的對比(轉)物件
- 12 Python物件導向程式設計:運算子過載Python物件程式設計
- SICP:構造過程抽象--物件導向的解釋抽象物件