Лучшие практики для написания элегантного кода

Java задняя часть алгоритм WeChat

Роберт Мартин как-то сказал, что «частота ругательств при чтении кода — единственная мера качества кода». в то же время,Код должен быть написан таким образом, чтобы минимизировать время, необходимое для его понимания другими., что означает, что мы пишем код для людей, а не для машин. Итак, как написать элегантный код? Код может быть оптимизирован с идеологического уровня и определенного уровня навыков.Идеологический уровень относится к следованию принципам объектно-ориентированного проектирования.Этот вопрос знакомит с конкретными методами.

## 1. Всегда ли код максимально краток?

assert((!(bucket = findBucket(key))) || !bucket.isOccupied());

Приведенная выше строка кода, хотя и относительно короткая, трудно читаема. Для лучшего чтения делаем следующие модификации:

bucket = findBucket(key);
if(bucket != null){
  assert(!bucket.isOccupied());
}

Сокращение количества строк кода — хорошая цель, но сведение к минимуму чтения кода — лучшая цель..

2. Добавляйте комментарии к важным заявлениям

// Fast version of "hash = (65599*hash) + c"
hash = (hash << 6) + (hash << 16) - hash + c

Если приведенная выше строка кода не прокомментирована, мы вообще не знаем, что это значит, но с этой строкой комментария мы знаем, что производительность можно улучшить за счет операций сдвига.

## 3. Использование tmp tmp — это то, что мы часто используем.Например, две замены переменных стали соглашениями.

tmp = right;
right = left;
left = tmp;
String tmp = user.getName();
tmp += " " + user.getPhoneNumber();
tmp += " " + user.getEmail();
template.set("user_info",tmp);

4.i,j,k,iter,it: используется только для индексации или итерации цикла

i,j,k,iter,itВ отрасли стало нормой использовать индекс или итерацию цикла (i — это сокращение от индекса), например:

for(int i=0;i<100;i++){
  for(int j=0;j<100;j++){
    ......
  }
}

Iterator<String> iter = list.iterator();
while(iter.hasNext()){
  ......
}

Если мы будем использовать i,j,k в другом месте, это увеличит время чтения.

5. Поставляется с важными атрибутами

Мы относимся к неймингу как к способу комментирования, делая его более информативным!

image.png

6. Какой длины должно быть имя?

  • Используйте короткие имена в небольших областях
  • Длинные имена можно использовать в больших областях.
if(debug){
  Map<String,Integer> m = new HashMap<>();
  lookUpNamesNumbers(m);
  print(m);
}

7. Не используйте вводящие в заблуждение имена

results = Database.all_objects.filter("year<=2011")

Какую информацию теперь содержит результат приведенной выше строки кода? фильтр для фильтрации данных, чей год меньше или равен 2011 году? Или сохранить?

8. Рекомендуется использовать минимальное и максимальное значение для представления предела.

MAX_ITEMS_IN_CART = 10;

if (shoppingCart.numOfItems()> MAX_ITEMS_IN_CART){
    error("Too many items in cart");
}

9. Рекомендуется использовать begin и end для указания области включения/исключения.

image.png
begin означает включение, end означает исключение, типичным примером в Java является String.substring()


String s = "Hello world";

s.substring(2,5);-> "llo"

10. Соответствуйте ожиданиям пользователей

В общем, геттер-метод предназначен для получения значения поля.Пользователи ожидают легковесного метода.Если вы выполняете слишком много вычислений в нем, вам следует подумать об изменении имени.


public double getMeanPrice(){

//遍历所有条目计算总价,然后计算平均价格

}

public double computeMeanPrice(){

//遍历所有条目计算总价,然后计算平均价格

}

11. Не пишите комментарии к фактам, которые можно быстро вывести из самого кода.


public  class Account {  

    // Constructor

   public  Account(){

   }

   // Set the profit member to a new value    

   void setProfit(double profit){

         …….

   }   

    // Return the profit from this Account    

    double getProfit(){

        ….

    }

};

12. Не комментируйте плохие имена — меняйте их

// Releases the handle for this key.This doesn't modify the actual registry.
void deleteRegistry(RegistryKey key)

На первый взгляд мы можем принять это за функцию, удаляющую реестр, но в комментариях поясняется, что она не изменяет реальный реестр. Поэтому мы можем использовать более понятное имя, например:

void releaseRegistryHandle(registryKey key);

13. Пишите комментарии к недостаткам вашего кода

// TODO: использовать более быстрый алгоритм или когда код не закончен // TODO(dustin): обработка изображений в форматах, отличных от JPEG

image.png

14. Пишите комментарии для констант

// users thought 0.72 gave the best size/quality tradeoff
image_quality = 0.72;

// as long as it's >= 2*num_processors,that's good enough
NUM_THREADS = 8;

// impose a reasonable limit - no human can read that much anywhere
const int MAX_RSS_SUBSCRIPTIONS = 1000;

15. Пишите заметки с точки зрения читателя

struct Recoder {
    vector<float> data;
    ......
    void clear(){
        // 每个人读到这里都会问,为啥不直接调用data.clear()
        vector<float>().swap(data);
    }
}

Если есть хороший комментарий, чтобы ответить на вопрос читателя, измените вышеприведенное следующим образом: Заставить вектор фактически вернуть память в распределитель памяти, подробности см. в трюке подкачки STL.

16. Объявите о возможных подводных камнях

void sendMail(String to,String subject,String body);

Эта функция может занимать много времени, поскольку для отправки сообщений электронной почты требуется вызов внешнего сервера, что может привести к зависанию потока пользователя. Это описание нужно поместить в комментарий.

17. Порядок параметров в условных операторах

image.png
Общее правило: располагайте переменные слева, а константы справа. В более широком смысле,Поместите более стабильные переменные справа, большее изменение помещается слева. Например, if (length >= 10) вместо if (10 Приведенный выше принцип, похоже, не работает в случае сравнения без «размера»., например, чтобы убедиться, что параметр запроса имеет определенное значение:if ( request.getParameterValue("name")).equals("Brandon")), На данный момент константа "Брэндон" может избежать ситуации с нулевым указателем (верхний параметр не имеет имени или значение пусто).

18. Порядок блоков if/else

Спецификация написания if/else: во-первых, работайте с положительной логикой вместо отрицательной, например, if(ok) вместо if(!ok); во-вторых, работайте с простыми случаями, в которых выгодно, чтобы if и else обрабатывали код в одном и том же коде. экран виден.

19. Уменьшите вложенность, возвращаясь раньше

Используя механизм раннего возврата, уровень вложенности функций может быть меньше. Например, без использования раннего кода возврата:

static bool checkUserAuthority()
        {
            bool a, b, c, d, e;

            if (a)
            {
                if (b)
                {
                    if (c)
                    {
                        if (d)
                        {
                            if (e)
                            {
                                return true;
                            }
                        }
                    }
                }
            }

            return false;
        }

Используется код, возвращающий раньше:

static bool checkUserAuthority()
        {
            bool a, b, c, d, e;

            if (!a)
                return false;

            if (!b)
                return false;

            if (!c)
                return false;

            if (!d)
                return false;

            if (!e)
                return false;

            return true;
       
        }

##20. Повысьте читабельность с помощью «суммарных переменных»

if(request.user.id == document.owner_id){
    // user can edit this document ...
}

if(request.user.id != document.owner_id){
    // document is read-only...
}

Наблюдая, мы извлекаем переменнуюfinal boolean user_owns_document=(request.user.id == document.owner_id), то код можно изменить на:

if(user_owns_document){
 // user can edit this document ...
}
if(!user_owns_document){
    // document is read-only...
}

21. Уменьшите переменные потока управления

В операторах цикла, таких как while и for, мы обычно используем настраиваемые логические переменные для управления потоком.

boolean done = false;
while(/* condition */ && !done){
    ...
    if(...){
        done = true;
        continue;
    }
}

По нашему опыту, «переменные потока управления» можно устранить путем оптимизации структуры программы, логики.

while(/* condition */){
    ...
    if(...){
        break;
    }
}

22. Уменьшите область действия переменных

void foo(){
    int i = 7;

    if(someCondition){
        // i is used only within this block
    }

}

void foo(){
    if(someCondition){
        int i = 7;
        // i is used only within this block
    }
}

23. Не устанавливайте переменные в качестве полей класса для совместного использования

public class LargeClass{
    String s;
    void method1(){
        s = ...
        method2();
    }
    void method2(){
        //使用s
    }
}

Обмен данными через передачу параметров

public class LargeClass{
    void method1(){
        String s = ...
        method2(s);
    }
    void method2(String s){
        //使用s
    }
}

24. Не определяйте все переменные в начале

Определение всех переменных в начале — это стиль C, а объектно-ориентированные языки имеют привычку определять переменные далеко от того места, где они используются.

public void foo(){
  boolean debug = false;
  String[] pvs;
  String pn;
  String pv;
  ...
}

В дополнение к приведенным выше предложениям мы также можем обратиться к спецификации Ali Java,Обратите внимание на WeChat: «Му Ке Да», отправьте «Спецификацию Ali Java», чтобы получить соответствующую информацию.


image

Добро пожаловать в общедоступную учетную запись WeChat: Mu Keda, все статьи будут синхронизированы в общедоступной учетной записи.