根据《代码之丑》系列内容示例代码:
1. 长函数
问题代码
public void executeTask() {
ObjectMapper mapper = new ObjectMapper();
CloseableHttpClient client = HttpClients.createDefault();
List<Chapter> chapters = this.chapterService.getUntranslatedChapters();
for (Chapter chapter : chapters) {
// 发送章节
SendChapterRequest sendChapterRequest = new SendChapterRequest();
sendChapterRequest.setTitle(chapter.getTitle());
sendChapterRequest.setContent(chapter.getContent());
HttpPost sendChapterPost = new HttpPost(sendChapterUrl);
CloseableHttpResponse sendChapterHttpResponse = null;
String chapterId = null;
try {
String sendChapterRequestText = mapper.writeValueAsString(sendChapterRequest);
sendChapterPost.setEntity(new StringEntity(sendChapterRequestText));
sendChapterHttpResponse = client.execute(sendChapterPost);
// ... 更多HTTP处理代码
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// ... 资源清理代码
}
// 翻译章节
// ... 类似的重复HTTP处理代码
}
}
重构后代码
public void executeTask() {
ObjectMapper mapper = new ObjectMapper();
CloseableHttpClient client = HttpClients.createDefault();
List<Chapter> chapters = this.chapterService.getUntranslatedChapters();
for (Chapter chapter : chapters) {
String chapterId = sendChapter(mapper, client, chapter);
translateChapter(mapper, client, chapterId);
}
}
private String sendChapter(ObjectMapper mapper, CloseableHttpClient client, Chapter chapter) {
SendChapterRequest request = asSendChapterRequest(chapter);
return executeHttpRequest(mapper, client, request, sendChapterUrl, SendChapterResponse.class);
}
private SendChapterRequest asSendChapterRequest(Chapter chapter) {
SendChapterRequest request = new SendChapterRequest();
request.setTitle(chapter.getTitle());
request.setContent(chapter.getContent());
return request;
}
2. 大类
问题代码
public class User {
private long userId;
private String name;
private String nickname;
private String email;
private String phoneNumber;
private AuthorType authorType; // 作者相关
private ReviewStatus authorReviewStatus; // 作者相关
private EditorType editorType; // 编辑相关
// ... 更多混合字段
// 用户基本行为
public void changePassword() { ... }
// 作者行为
public void submitBook() { ... }
// 编辑行为
public void reviewChapter() { ... }
}
重构后代码
public class User {
private long userId;
private String name;
private String nickname;
private Contact contact;
public void changePassword() { ... }
}
public class Contact {
private String email;
private String phoneNumber;
}
public class Author {
private long userId;
private AuthorType authorType;
private ReviewStatus reviewStatus;
public void submitBook() { ... }
}
public class Editor {
private long userId;
private EditorType editorType;
public void reviewChapter() { ... }
}
3. 长参数列表
问题代码
public void createBook(final String title,
final String introduction,
final URL coverUrl,
final BookType type,
final BookChannel channel,
final String protagonists,
final String tags,
final boolean completed) {
// ... 参数太多,难以维护
}
重构后代码
public void createBook(final NewBookParameters parameters) {
Book book = parameters.newBook();
this.repository.save(book);
}
public class NewBookParameters {
private String title;
private String introduction;
private URL coverUrl;
private BookType type;
private BookChannel channel;
private String protagonists;
private String tags;
private boolean completed;
public Book newBook() {
return Book.builder()
.title(title)
.introduction(introduction)
// ... 其他字段
.build();
}
}
4. 滥用控制语句
问题代码(嵌套过深)
public void distributeEpubs(final long bookId) {
List<Epub> epubs = this.getEpubsByBookId(bookId);
for (Epub epub : epubs) {
if (epub.isValid()) {
boolean registered = this.registerIsbn(epub);
if (registered) {
this.sendEpub(epub);
}
}
}
}
重构后代码(卫语句)
public void distributeEpubs(final long bookId) {
List<Epub> epubs = this.getEpubsByBookId(bookId);
for (Epub epub : epubs) {
this.distributeEpub(epub);
}
}
private void distributeEpub(final Epub epub) {
if (!epub.isValid()) {
return;
}
if (!this.registerIsbn(epub)) {
return;
}
this.sendEpub(epub);
}
问题代码(重复switch)
public double getBookPrice(User user, Book book) {
switch (user.getLevel()) {
case SILVER: return book.getPrice() * 0.9;
case GOLD: return book.getPrice() * 0.8;
case PLATINUM: return book.getPrice() * 0.75;
default: return book.getPrice();
}
}
public double getEpubPrice(User user, Epub epub) {
switch (user.getLevel()) {
case SILVER: return epub.getPrice() * 0.95;
case GOLD: return epub.getPrice() * 0.85;
case PLATINUM: return epub.getPrice() * 0.8;
default: return epub.getPrice();
}
}
重构后代码(多态)
interface UserLevel {
double getBookPrice(Book book);
double getEpubPrice(Epub epub);
}
class SilverUserLevel implements UserLevel {
public double getBookPrice(Book book) {
return book.getPrice() * 0.9;
}
public double getEpubPrice(Epub epub) {
return epub.getPrice() * 0.95;
}
}
// 使用
public double getBookPrice(User user, Book book) {
return user.getUserLevel().getBookPrice(book);
}
5. 缺乏封装
问题代码(火车残骸)
String name = book.getAuthor().getName();
重构后代码
class Book {
public String getAuthorName() {
return this.author.getName();
}
}
String name = book.getAuthorName();
问题代码(基本类型偏执)
public class Order {
private double total; // 直接用基本类型
public void setTotal(double total) {
if (total < 0) {
throw new IllegalArgumentException("价格不能为负");
}
this.total = total;
}
}
重构后代码
public class Order {
private Money total;
public Order(Money total) {
this.total = total;
}
}
public class Money {
private final double amount;
private final String currency;
public Money(double amount, String currency) {
if (amount < 0) {
throw new IllegalArgumentException("金额不能为负");
}
this.amount = amount;
this.currency = currency;
}
public double getDisplayPrice() {
// 统一格式化逻辑
return BigDecimal.valueOf(amount)
.setScale(2, RoundingMode.HALF_UP)
.doubleValue();
}
}
6. 可变数据
问题代码(setter滥用)
public void approve(final long bookId) {
Book book = repository.findById(bookId);
book.setReviewStatus(ReviewStatus.APPROVED); // 暴露内部状态
repository.save(book);
}
重构后代码
public void approve(final long bookId) {
Book book = repository.findById(bookId);
book.approve(); // 封装状态变更
repository.save(book);
}
class Book {
private ReviewStatus reviewStatus;
public void approve() {
this.reviewStatus = ReviewStatus.APPROVED;
}
// 或者设计为不变类
public Book approve() {
return new Book(..., ReviewStatus.APPROVED, ...);
}
}
7. 重复代码
问题代码(结构重复)
@Task
public void sendBook() {
try {
this.service.sendBook();
} catch (Throwable t) {
this.notification.send(new SendFailure(t)));
throw t;
}
}
@Task
public void sendChapter() {
try {
this.service.sendChapter();
} catch (Throwable t) {
this.notification.send(new SendFailure(t)));
throw t;
}
}
重构后代码
private void executeTask(Runnable task) {
try {
task.run();
} catch (Throwable t) {
this.notification.send(new SendFailure(t)));
throw t;
}
}
@Task
public void sendBook() {
executeTask(this.service::sendBook);
}
@Task
public void sendChapter() {
executeTask(this.service::sendChapter);
}
8. 不一致的代码
问题代码(命名不一致)
enum DistributionChannel {
WEBSITE, // 没有_ONLY
KINDLE_ONLY, // 有_ONLY
ALL
}
重构后代码
enum DistributionChannel {
WEBSITE, // 统一命名
KINDLE, // 去掉_ONLY
ALL
}
问题代码(方案不一致)
// 混合使用新旧日期API
public String nowTimestamp() {
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now = new Date(); // 旧API
return format.format(now);
}
重构后代码
public String nowTimestamp() {
LocalDateTime now = LocalDateTime.now(); // 新API
return now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
9. 依赖混乱
问题代码(缺少防腐层)
@PostMapping("/books")
public NewBookResponse createBook(final NewBookRequest request) {
// 直接传递接口层对象到业务层
boolean result = this.service.createBook(request);
// ...
}
重构后代码
@PostMapping("/books")
public NewBookResponse createBook(final NewBookRequest request) {
// 转换为业务参数
NewBookParameter parameter = request.toNewBookParameter();
boolean result = this.service.createBook(parameter);
// ...
}
public class NewBookRequest {
public NewBookParameter toNewBookParameter() {
return new NewBookParameter(this.title, this.introduction, ...);
}
}
10. 变量声明与赋值分离
问题代码
EpubStatus status = null; // 假初始化
CreateEpubResponse response = createEpub(request);
if (response.getCode() == 201) {
status = EpubStatus.CREATED;
} else {
status = EpubStatus.TO_CREATE;
}
重构后代码
final CreateEpubResponse response = createEpub(request);
final EpubStatus status = toEpubStatus(response);
private EpubStatus toEpubStatus(final CreateEpubResponse response) {
return response.getCode() == 201 ?
EpubStatus.CREATED : EpubStatus.TO_CREATE;
}
问题代码(集合初始化)
List<Permission> permissions = new ArrayList<>(); // 未完成初始化
permissions.add(Permission.BOOK_READ);
permissions.add(Permission.BOOK_WRITE);
check.grantTo(Role.AUTHOR, permissions);
重构后代码
List<Permission> permissions = List.of(
Permission.BOOK_READ,
Permission.BOOK_WRITE
);
check.grantTo(Role.AUTHOR, permissions);
11. 使用新语言特性
问题代码(空指针风险)
String name = book.getAuthor().getName(); // 可能NPE
重构后代码(Optional)
class Book {
public Optional<Author> getAuthor() {
return Optional.ofNullable(this.author);
}
}
String name = book.getAuthor()
.map(Author::getName)
.orElse("Unknown");
问题代码(传统循环)
public ChapterParameters toParameters(List<Chapter> chapters) {
List<ChapterParameter> parameters = new ArrayList<>();
for (Chapter chapter : chapters) {
if (chapter.isApproved()) {
parameters.add(toChapterParameter(chapter));
}
}
return new ChapterParameters(parameters);
}
重构后代码(函数式)
public ChapterParameters toParameters(List<Chapter> chapters) {
List<ChapterParameter> parameters = chapters.stream()
.filter(Chapter::isApproved)
.map(this::toChapterParameter)
.collect(Collectors.toList());
return new ChapterParameters(parameters);
}
这些示例展示了如何识别和修复各种代码坏味道,核心思想是:封装、单一职责、减少重复、提高表达性。每个重构都让代码更易于理解、测试和维护。