предисловие
Из-за моего характера автору трудно успокоиться и заняться серьезным систематическим изучением.Мне всегда нравится подбрасывать какие-то странные приемы.Мне очень нравится дизайн кода и вычитать детали кода,поэтому в этот раз я поделюсь тем,что я знать.如何写最少的代码
Если у вас есть лучшее решение, пожалуйста, оставьте сообщение в области комментариев,方案很棒的话,加我微信,为你送上冬天的一杯奶茶~
Java: я хочу вернуть несколько возвращаемых значений
покажи этоGo
Множественные возвращаемые значения:
package main
import "fmt"
// 返回 X + Y 和 X * Y
func Computer(X, Y int) (int, int) {
return X + Y, X * Y
}
Как мы все знаем, Java поддерживает только одно возвращаемое значение.Как правило, если нам нужно вернуть несколько объектов, мы выбираем контейнер в соответствии с семантикой кода или создаем новый класс для упаковки нужных нам данных.
这样做有没有问题?
Конечно, проблемы нет, но недостаток в том, что семантики может и не быть, но она должна существовать.中间类
, я лично очень много обсуждаю такой код, так как решить такую проблему?
Первое, что нужно осознать, это то, что решение должно отвечать нескольким требованиям:
- Код можно использовать повторно
- Семантика должна быть ясной
- Безопасность
В таком случае мы можем использовать泛型
Чтобы удовлетворить требования повторного использования и четкой семантики, используйте中间类
Чтобы соответствовать требованиям безопасности кода, код выглядит следующим образом:
public class MultipleTwoReturn<A, B> {
/** 第一个返回值 **/
private final A first;
/** 第二个返回值 **/
private final B second;
public MultipleTwoReturn(A first, B second) {
this.first = first;
this.second = second;
}
// 省略Get方法
}
В то же время мы можем положиться на继承
, пусть класс инструмента расширяет дополнительные параметры:
public class MultipleThreeReturn<A, B, C> extends MultipleTwoReturn<A, B> {
/** 第三个返回值 **/
private final C third;
public MultipleThreeReturn(A first, B second, C third) {
super(first, second);
this.third = third;
}
}
Тестовый класс:
public class MultipleApp {
public static void main(String[] args) {
MultipleTwoReturn<Integer, String> returnTest = MultipleApp.getReturnTest();
System.out.println(returnTest.getFirst());
System.out.println(returnTest.getSecond());
}
private static MultipleTwoReturn<Integer, String> getReturnTest() {
MultipleTwoReturn<Integer, String> demo = new MultipleTwoReturn<>(0, "Kerwin Demo.");
return demo;
}
}
По существу все еще普通对象
, но добавив泛型
После мощность резко возрастает! Поскольку он применяется, когда метод определен泛型约束
, семантика очень понятна, и в то же время, упомянутые выше несемантические промежуточные классы могут быть полностью исключены.Конечно, некоторые необходимые ассемблерные классы с бизнес-значениями использовать этот метод не рекомендуется.
Дженерики: я хочу создать новый объект
У вас возникла эта идея, когда вы изучали дженерики Java? Я хочу использовать как общее ограничение, но мне нужноnew
ОдинT
, но Java этоnew
не могу выйти 😂
Давным-давно я писал общийJava爬虫接口
, у которого есть функция,传入目标网页的即可获取到针对不同网页设计的Bean
, примерно так:
public interface SpiderBeansHandle<T> {
/** 获取Url **/
String getUrl();
/** 获取Cookie **/
String getCookie();
/** 获取CSS selector **/
String getSelector();
// ....
}
Ключевым моментом посередине является то, как получить этот Бин, В то время у меня была только одна идея:new 一个 T
Оказывается, я был слишком наивен 🙄
Но другой способ мышления, посколькуnew
Если не выйдет, то вернусь, так что код выложен~
public interface SpiderBeansHandle<T> {
/**
* 获取Url
*/
String getUrl();
/**
* 获取Cookie
*/
String getCookie();
/***
* 获取CSS selector
*/
String getSelector();
/***
* 解析Element
* @param element element
*/
T parseElement(Element element);
/***
* Get Beans
* @param handle Bean对象 | handle对象
* @param <T> Bean类型
* @return List<Beans>
*/
static <T> List<T> getBeans(SpiderBeansHandle<T> handle) {
List<T> list = new ArrayList<>();
List<Element> elements = SpiderUtils.getElementWithCookie(handle.getUrl(), handle.getSelector(), handle.getCookie());
for (Element element : elements) {
T bean = handle.parseElement(element);
if (bean != null) {
list.add(bean);
}
}
return list;
}
}
Ключевым шагом является:
/***
* 解析Element
* @param element element
*/
T parseElement(Element element);
Так в чем польза от этой маленькой хитрости? Если присмотреться, похоже ли это на деформатор шаблона проектирования? Верно! есть только одна истина:模板方法模式
Я только что упомянул, что мне нужно处理爬虫的通用接口
, потому что простой поисковый робот — это не что иное, как получение URL-адреса, его запрос, инкапсуляция деталей синтаксического анализа в свой собственный bean-компонент, а затем получение списка, поэтому при разработке бизнес-кода он аналогичен Должны быть некоторые сценарии и требования, которые сильно последовательно, затем используйте эту схему проектирования, которая может значительно уменьшить дублирование кода~
Метод: Что вы хотите сделать?
Сталкивались ли мы с такой проблемой при написании кода? Я написал метод класса инструмента, но функция слишком одиночная.Хотя один принцип это хорошо, но небольшая логика, чтобы написать кучу методов, мне всегда плохо, как это решить?
Функциональное программирование, предоставляемое Java8, может помочь нам решить эту проблему в определенной степени, например:
// 写一个获取文件列表,且判断是否为txt结尾的工具类方法,新手会这么写
public static File getFileWithTxt(String path) throws IOException {
File file = new File(path);
if (!file.exists()) {
throw new IOException("File is not exist.");
}
if (file.getName().endsWith(".txt")) {
return file;
}
return null;
}
Ветераны обычно.txt
Передайте в качестве параметра,但是某一天我需要判断文件大小,文件长度,甚至是文件内容的时候,我该咋办?再写N个?
Лучшее решение - пройтиPredicate
предикат, пусть вызывающий自定义处理逻辑
, а затем переписать наиболее часто используемую логику на основе этого метода, расширяемого Max! код показывает, как показано ниже:
/***
* 文件夹谓词匹配
* @param file 文件
* @param predicate 谓词匹配
* @return List<File>
* @throws IOException IOException
*/
public static List<File> listFilesInDirWithFilter(File file, Predicate<String> predicate) throws IOException {
if (!file.exists()) {
throw new IOException("File is not exist.");
}
List<File> fileList = new ArrayList<>();
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : Objects.requireNonNull(files)) {
fileList.addAll(listFilesInDirWithFilter(f, predicate));
}
} else {
if (predicate.test(file.getName())) {
fileList.add(file);
}
}
return fileList;
}
Так же, например, обработкаIO
, непосредственно в коде:
public static void readLine(BufferedReader br, Consumer<String> handle, boolean close) {
String s;
try {
while (((s = br.readLine()) != null)) {
handle.accept(s);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (close && br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
方法
Скажи, что ты хочешь? ! Забудь об этом, делай, что хочешь, пожалуйста, не стесняйся 😎~
Перегрузка: пишите больше, чтобы писать меньше
写的更多也是为了写的更少
, это предложение поначалу звучит очень противоречиво, но маленький партнер с богатым опытом программирования должен быть в состоянии понять方法重载
Мощь , особенно при написании классов инструментов или низкоуровневых интерфейсов, рекомендуется написать большой и всеобъемлющий内部方法
, а потом немного перезагрузить его по мере надобности, будет неожиданная польза.
Самый простой пример выглядит следующим образом:
// Root 方法
private static void readLine(BufferedReader br, Consumer<String> handle, boolean close) {
String s;
try {
while (((s = br.readLine()) != null)) {
handle.accept(s);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (close && br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 重载方法一
public static void readLine(String path, Consumer<String> handle, boolean close) {
try {
BufferedReader br = new BufferedReader(new FileReader(path));
readLine(br, handle, close);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
// 重载方法二
public static void readLine(String path, Consumer<String> handle) {
readLine(path, handle, true);
}
重载
Это может сделать наши методы, вызывающие методы, красочными.В случае ясной семантики написание кода подобно богу.С функциональным программированием возможности классов инструментов или базовых интерфейсов могут быть значительно улучшены.
В то же время, когда нам нужно настроить логику метода, мы также можем использовать继续重载
способ минимизировать влияние и постараться не перемещать код других модулей.
Ultimate: от шаблонов проектирования к абстракции
скорее, чем如何写最少的代码
, скорее:如何只写真正有价值的代码
.
При столкновении с такого рода проблемами нашей первой реакцией должны быть шаблоны проектирования, такие как упомянутые выше в разделе об обобщениях.模板方法模式
, небольшая рекомендация моих предыдущих статей:
- [Серия «Учимся вместе»] Шаблонный метод: мне нужно всего 5 минут, чтобы написать систему единого входа
- Шаблоны проектирования в целом: от того, зачем нужны принципы, до фактической реализации
Благодаря хорошим шаблонам проектирования или их вариантам мы можем получить код с высокой связностью и низкой связанностью, что является очень хорошей идеей.
Еще одна мысль, все согласны в одном:程序 = 算法 + 数据结构
, выбрав правильную структуру данных, можно получить вдвое больший результат, затрачивая половину усилий.类似文件夹需求
когда вы думаете об использовании链表
или树
структуру, делая что-то вроде:如何高效的给用户发送生日短信
подумайте об использовании堆
Структура (сравните максимальное значение в куче с текущим временем, если оно устраивает, продолжайте итерацию, уменьшите обход) и так далее.
На самом деле это все абстрактно, либо глубоко, либо поверхностно.Когда я только начинал изучать Java, учитель говорил что-то: все является объектом, давайте посмотрим, чему соответствуют вышеприведенные приемы?
- Несколько возвращаемых значений: инкапсулированные объекты + общие ограничения
- Generics: инкапсулировать общедоступный интерфейс объекта, очень абстрактный
- Функциональные методы: рассматривайте метод как объект
- Перегрузка: непрерывная эволюция методов объекта (поведения)
Так как же писать только действительно ценный код? Официальное слово:把变化的抽象出来
, тогда как рисовать?
Это требует от нас немного изучить, в конце концов奇淫技巧
Просто маленький Дойл, но я продолжу исследования.
Наконец
Если вы считаете этот контент полезным:
- Конечно, ставьте лайки и поддерживайте~
- Кроме того, ищите и подписывайтесь на официальный аккаунт »это Кервин", пойдем по дороге технологий вместе~ 😋