15 มีนาคม 2567

วิธีปรับปรุงคุณภาพโค้ด Java เมื่อใช้นักแปลของเรา

เราจะพูดถึงแนวทางและโครงสร้างภาษาใน C#: อันไหนดีและอันไหนไม่ดี แน่นอนว่าไม่ว่าจะดีหรือไม่ดี เราจะพิจารณาสิ่งต่อไปนี้: โค้ด Java สามารถอ่านและบำรุงรักษาได้เพียงใดหลังจากการแปลจาก C#

กะทัดรัดใน C# – ใหญ่ใน Java

C# มีโครงสร้างภาษาขนาดกะทัดรัดที่ทำงานซ่อนอยู่มากมาย เมื่อคุณแปลโครงสร้างเหล่านั้นเป็นภาษาอื่น คุณจะต้องทำซ้ำส่วนที่ซ่อนอยู่นั้นโดยปริยาย และในกรณีส่วนใหญ่ โค้ดจะสูญเสียการออกแบบดั้งเดิมและแตกต่างอย่างมาก

คุณสมบัติอัตโนมัติ

คุณสมบัติอัตโนมัติมีการใช้งานอย่างกว้างขวางในหมู่โปรแกรมเมอร์ C# การใช้โปรแกรมเมอร์คุณสมบัติประเภทนั้นสามารถโต้ตอบกับฟิลด์ที่ซ่อนอยู่ผ่านเมธอด get และ/หรือ set C# ช่วยให้เราหันเหความสนใจจากการใช้งานจริงของคุณสมบัติอัตโนมัติและใช้โครงสร้างที่กะทัดรัดมากในการประกาศ แต่ใน Java เราไม่มีโครงสร้างภาษาดังกล่าว และจำเป็นต้องประกาศคุณสมบัติอย่างชัดเจน: เป็นวิธีการควบคุมฟิลด์และการเข้าถึง:

public int Value { get; set; }

ใน Java กลายเป็น:

private int auto_Value;
public int get_Value()
{
    return auto_Value;
}
public void set_Value(int value)
{
    auto_Value = value;
}

ตอนนี้ไม่ใช่สมาชิกที่มั่นคงเพียงตัวเดียว แต่มีสมาชิกแยกกันสามตัว ลองนึกภาพโค้ดเดียวกันที่ทำซ้ำสำหรับพร็อพเพอร์ตี้อัตโนมัติแต่ละรายการ จะมีหน้าตาเป็นอย่างไร ให้เราหลีกเลี่ยงประสบการณ์อันไม่พึงประสงค์ดังกล่าว แต่อย่างไร?
พยายามแทนที่คุณสมบัติอัตโนมัติด้วยวัตถุที่ให้การควบคุมการเข้าถึงฟิลด์ส่วนตัว อาจมีแฮชแมปของวัตถุดังกล่าว หากเราปฏิบัติตามการออกแบบการเข้าถึงข้อมูลบางอย่างอย่างจำกัด นั่นอาจเป็นวิธีที่ดี คุณสมบัติอัตโนมัติอาจดูดี แต่เราไม่จำเป็นต้องใช้โดยไม่จำเป็น

ประเภทค่า

ใน C# เรามีตรรกะหน่วยความจำเฉพาะสำหรับโครงสร้าง (ประเภทค่า) อายุการใช้งานถูกจำกัดด้วยอายุการใช้งานของเฟรมสแต็กหรือวัตถุที่บรรจุ และพวกมันจะถูกคัดลอกบ่อยครั้ง เมื่อเราส่งพวกมันเป็นอาร์กิวเมนต์ของฟังก์ชัน ส่งกลับจากฟังก์ชัน หรือกำหนดให้กับบางฟิลด์ เราจะดำเนินการด้วยค่า ไม่ใช่การอ้างอิง การเปลี่ยนสำเนาเราไม่เปลี่ยนต้นฉบับ ในการแปลประเภทค่าเป็น Java เราต้องสร้างตรรกะเดียวกันขึ้นมาใหม่ แม้ว่าคลาส Java จะเป็นประเภทอ้างอิงเสมอก็ตาม การคัดลอกบ่อยครั้งกลายเป็นปัญหาในขณะนี้ เพื่อจัดเก็บแต่ละสำเนา เราจัดสรรหน่วยความจำจากฮีป ทำให้ตัวรวบรวมขยะทำงานหนักเกินไป หากเราถือว่าประสิทธิภาพเป็นหนึ่งในความสนใจของเรา เราจะต้องสรุปโค้ด C# ของเราจากรายละเอียดการจัดการหน่วยความจำ แต่อย่างไร?
วิธีที่ง่ายที่สุดในการทำเช่นนั้น – ทำให้ประเภทค่าของคุณไม่เปลี่ยนรูป เมื่อคุณไม่มีสถานะที่ไม่แน่นอน คุณไม่จำเป็นต้องคัดลอกสถานะนั้นเพื่อป้องกันพฤติกรรมที่ไม่ได้กำหนดไว้

โครงสร้างไวยากรณ์เท่านั้น

ตอนนี้เป็นเวลาที่จะพูดคุยเกี่ยวกับโครงสร้างภาษาที่เปลี่ยนแปลงเฉพาะคุณสมบัติการมองเห็นของโค้ด แต่ไม่ใช่พฤติกรรม ตัวอย่างเช่น:

public class Item
{
    string name;
    string price;
    
    public Item(string name, int price) => (this.name, this.price) = (name, price);
    
    public string ToString() => $"Name = {name}, Price = {price}";
    public string Name => name;
    public int Price => price;
}

เราเห็นโครงสร้างของทูเปิลที่นี่ (นิพจน์นั้นไม่ได้สร้างทูเปิลจริงๆ) สตริงลิเทอรัลที่ประมาณค่า วิธีการและคุณสมบัติของนิพจน์

ผู้ได้รับมอบหมาย

ผู้รับมอบสิทธิ์ใช้งานได้ดีเนื่องจากเป็นรูปแบบสั้นๆ ของการประกาศวิธีการ ให้เราดูตัวอย่าง:

using System;
using System.Linq;

class Program
{
    delegate int ChangeNumber(int arg);
	static void Main()
	{
	    Console.WriteLine("Input some numbers");
        int[] numbers = Console.ReadLine().Split(" ").Select(int.Parse).ToArray();
        Console.WriteLine("Input addition");
        int addition = int.Parse(Console.ReadLine());
        ChangeNumbers(n => n + addition, numbers);
        Console.WriteLine("Result :");
        Console.WriteLine(string.Join(" ", numbers.Select(n => n.ToString())));
	}
	static void ChangeNumbers(ChangeNumber change, int[] numbers)
	{
	    for(int i = 0; i < numbers.Length; i++)
	    {
	        numbers[i] = change(numbers[i]);
	    }
	}
}

สำหรับนิพจน์ n => n + addition นั้น เราอาจสร้างนิพจน์คลาสที่ไม่ระบุชื่อ Java:

// translated to Java code
interface ChangeNumber
{
    int invoke(int arg);
}
// ...static void main(String[] args)...

// anonymous class expression for Java 7 or older version
changeNumbers(new ChangeNumber()
{
    public int invoke(int n)
    {
        return n + addition;
    }
}, numbers);

// or lambda expression for higher Java 8 or newer version
changeNumbers(n -> n + addition, numbers);

บทสรุป

C# มีโครงสร้างภาษามากมาย ซึ่งอาจทำให้โค้ดของเราดูเรียบง่าย โดยซ่อนการใช้งานขนาดใหญ่ไว้เบื้องหลังไวยากรณ์ โครงสร้างบางส่วนนั้นน่าสงสัยและแทบจะไม่รองรับ ส่วนโครงสร้างอื่นๆ มีความยืดหยุ่นและทำซ้ำได้ง่าย เมื่อพูดถึงการออกแบบ การเขียนนามธรรมด้วยอ็อบเจ็กต์จะดีกว่า ไม่ใช่ด้วยโครงสร้างภาษา C# โดยเฉพาะ เมื่อพูดถึงประสิทธิภาพ เราควรละทิ้งสิ่งที่เป็นนามธรรมจากการจัดการหน่วยความจำ ปลดปล่อยตัวเองจากการเลียนแบบสิ่งนั้นด้วยต้นทุนสองเท่า

ข่าวที่เกี่ยวข้อง

บทความที่เกี่ยวข้อง