程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java和Ceylon對象的結構和驗證

Java和Ceylon對象的結構和驗證

編輯:關於JAVA

Java和Ceylon對象的結構和驗證。本站提示廣大學習愛好者:(Java和Ceylon對象的結構和驗證)文章只能為提供參考,不一定能成為您想要的結果。以下是Java和Ceylon對象的結構和驗證正文


當變換Java代碼為Ceylon代碼時,有時分我會遇到一些Java類結構器混雜了驗證與初始化的情形。讓我們運用一個復雜但是人為的代碼例子來闡明我想論述的意思。

一些壞代碼

思索上面的Java類。(伙計,不要在家裡寫這樣的代碼)

public class Period {
 private final Date startDate;
 private final Date endDate;
 //returns null if the given String
 //does not represent a valid Date
 private Date parseDate(String date) {
  ...
 }
 public Period(String start, String end) {
  startDate = parseDate(start);
  endDate = parseDate(end);
 }
 public boolean isValid() {
  return startDate!=null && endDate!=null;
 }
 public Date getStartDate() {
  if (startDate==null) 
   throw new IllegalStateException();
  return startDate;
 }
 public Date getEndDate() {
  if (endDate==null)
   throw new IllegalStateException();
  return endDate;
 }
}

嘿,我之前曾經正告過,它是人為的。但是,在實踐Java代碼中找個像這樣的東西實踐上並非不罕見。

這裡的問題在於,即便輸出參數(在隱藏的parseDate()辦法中)的驗證失敗了,我們還是會取得一個Period的實例。但是我們獲取的那個Period不是一個“無效的”形態。嚴厲地說,我的意思是什麼呢?

好吧,假設一個對象不能有意義地呼應公用操作時,我會說它處於一個非無效形態。在這個例子裡,getStartDate() 和getEndDate()會拋出一個IllegalStateException異常,這就是我以為不是“有意義的”一種狀況。

從另外一方面來看這個例子,在設計Period時,我們這兒呈現了類型平安的失敗。未反省的異常代表了類型零碎中的一個“破綻”。因而,一個更好的Period的類型平安的設計,會是一個不運用未反省的異常—在這個例子中意味著不拋出IllegalStateException異常。

(實踐上,在真實代碼中,我更有能夠遇到一個getStartDate() 辦法它不反省null ,在這個代碼行之後就會招致一個NullPointerException異常,這就愈加蹩腳了。)

我們可以很容易地轉換下面的Period類成為Ceylon方式的類:

shared class Period(String start, String end) {
 //returns null if the given String
 //does not represent a valid Date
 Date? parseDate(String date) => ... ;
 value maybeStartDate = parseDate(start);
 value maybeEndDate = parseDate(end);
 shared Boolean valid
  => maybeStartDate exists 
  && maybeEndDate exists;
 shared Date startDate {
  assert (exists maybeStartDate);
  return maybeStartDate;
 }
 shared Date endDate {
  assert (exists maybeEndDate);
  return maybeEndDate;
 }
}

當然了,這段代碼也會遇到與原始Java代碼異樣的問題。兩個assert符號沖著我們大喊,在代碼的類型平安中有一個問題。

使Java代碼變得更好

Java裡我們怎樣改良這段代碼呢?好吧,這兒就是一個例子關於Java飽受诟病的已反省異常會是一個十分合理的處理辦法!我們可以略微修正下Period來從它的結構器中拋出一個已反省的異常:

public class Period {
 private final Date startDate;
 private final Date endDate;
 //throws if the given String
 //does not represent a valid Date
 private Date parseDate(String date)
   throws DateFormatException {
  ...
 }
 public Period(String start, String end) 
   throws DateFormatException {
  startDate = parseDate(start);
  endDate = parseDate(end);
 }
 public Date getStartDate() {
  return startDate;
 }
 public Date getEndDate() {
  return endDate;
 }
}

如今,運用這個處理方案,我們就不會獲取一個處於非無效形態的Period,實例化Period的代碼會由編譯器擔任去處置有效輸出的情形,它會捕捉一個DateFormatException異常。

try {
 Period p = new Period(start, end);
 ...
}
catch (DateFormatException dfe) {
 ...
}

這是一個對已反省異常不錯的、完滿的、正確的運用,不幸的是我簡直很少看到Java代碼像下面這樣運用已反省異常。

使Ceylon代碼變得更好

那麼Ceylon怎樣樣呢?Ceylon沒有已反省異常,因此我們需求尋覓一個不同的處理方式。典型地,在Java調用一個函數會拋出一個已反省異常的情形中,Ceylon會調用函數前往一個結合類型。由於,一個類的初始化不前往除了類自己外的任何類型,我們需求提取一些混合的初始化/驗證的邏輯來使其成為一個工廠函數。

//returns DateFormatError if the given 
//String does not represent a valid Date
Date|DateFormatError parseDate(String date) => ... ;
shared Period|DateFormatError parsePeriod
  (String start, String end) {
 value startDate = parseDate(start);
 if (is DateFormatError startDate) {
  return startDate;
 }
 value endDate = parseDate(end);
 if (is DateFormatError endDate) {
  return endDate;
 }
 return Period(startDate, endDate);
}
shared class Period(startDate, endDate) {
 shared Date startDate;
 shared Date endDate;
}

依據類型零碎,調用者有義務去處置DateFormatError:

value p = parsePeriod(start, end);
if (is DateFormatError p) {
 ...
}
else {
 ...
}

或許,假如我們不關懷給定日期格式的實踐問題(這是有能夠的,假定我們任務的初始化代碼喪失了那個信息),我們可以運用Null而不是DateFormatError:

//returns null if the given String 
//does not represent a valid Date
Date? parseDate(String date) => ... ;
shared Period? parsePeriod(String start, String end)
 => if (exists startDate = parseDate(start), 
   exists endDate = parseDate(end))
  then Period(startDate, endDate)
  else null;
shared class Period(startDate, endDate) {
 shared Date startDate;
 shared Date endDate;
}

至多可以說,運用工廠函數的辦法是優秀的,由於通常來說在驗證邏輯和對象初始化之間它具有更好的隔離。這點在Ceylon中特別有用,在Ceylon中,編譯器在對象初始化邏輯中添加了一些十分嚴峻的限制,以保證對象的一切范疇僅被賦值一次。

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支持。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved