“ ข้อต่อหลวมคืออะไร” กรุณาให้ตัวอย่าง


172

ฉันดูเหมือนจะไม่สามารถห้อมล้อมแนวคิดของ "การแต่งงานกันอย่างหลวม ๆ " ฉันคิดว่ามันไม่ได้ช่วยว่าคำว่า "หลวม" มักจะมีความหมายเชิงลบดังนั้นฉันมักจะลืมว่าการมีเพศสัมพันธ์ที่หลวมเป็นสิ่งที่ดี

ใครสักคนโปรดแสดงรหัส "ก่อน" และ "หลัง" (หรือรหัสเทียม) ที่แสดงแนวคิดนี้


ฉันไม่แน่ใจว่าสิ่งนี้สามารถหย่าจากภาษาใดภาษาหนึ่งได้เพราะส่วนหนึ่งของแนวคิดคือวิธีที่หนึ่งใช้ภาษาในการป้องกันไม่ให้หน่วยโค้ดยุ่งเหยิงกันเกินไป ฉันยังทราบว่าหลายคำตอบหันไปใช้รหัสเพื่อแสดงแนวคิด
Onorio Catenacci

11
ไม่เห็นด้วยอย่างสมบูรณ์แนวปฏิบัติที่สามารถอธิบายได้แตกต่างกันในภาษาต่าง ๆ และเป็นที่ชัดเจนโดยเฉพาะอย่างยิ่งในภาษาแบบไดนามิกและคอมไพล์ vs แต่แนวคิดก็เหมือนกัน
โอเว่น

หลวม VS แน่นและCoupling VS Decoupling การแท็กตามไม่ใช่สิ่งที่ดีเสมอบางครั้งก็ดี / บางครั้งก็ไม่ดี ... เนื่องจากเราควรมีความเป็นอิสระของเราเอง
bonCodigo

คำตอบ:


180

พิจารณาแอปพลิเคชั่นตะกร้าสินค้าแบบง่ายที่ใช้คลาส CartContents เพื่อติดตามรายการในตะกร้าสินค้าและชั้นคำสั่งซื้อเพื่อประมวลผลการสั่งซื้อ คำสั่งซื้อจำเป็นต้องกำหนดมูลค่ารวมของเนื้อหาในรถเข็นซึ่งอาจเป็นเช่นนั้น:

ตัวอย่างที่กระชับอย่างแน่นหนา:

public class CartEntry
{
    public float Price;
    public int Quantity;
}

public class CartContents
{
    public CartEntry[] items;
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        float cartTotal = 0;
        for (int i = 0; i < cart.items.Length; i++)
        {
            cartTotal += cart.items[i].Price * cart.items[i].Quantity;
        }
        cartTotal += cartTotal*salesTax;
        return cartTotal;
    }
}

ขอให้สังเกตว่าวิธีการสั่งซื้อทั้งหมด (และระดับสั่งซื้อ) ขึ้นอยู่กับรายละเอียดการใช้งานของ CartContents และคลาส CartEntry ถ้าเราพยายามที่จะเปลี่ยนตรรกะนี้เพื่อให้ส่วนลดเราน่าจะต้องเปลี่ยนทั้ง 3 ชั้น นอกจากนี้หากเราเปลี่ยนไปใช้การรวบรวมรายชื่อเพื่อติดตามรายการเราจะต้องเปลี่ยนคลาสการสั่งซื้อด้วย

ต่อไปนี้เป็นวิธีที่ดีกว่าเล็กน้อยในการทำสิ่งเดียวกัน:

ตัวอย่างที่น้อยกว่า:

public class CartEntry
{
    public float Price;
    public int Quantity;

    public float GetLineItemTotal()
    {
        return Price * Quantity;
    }
}

public class CartContents
{
    public CartEntry[] items;

    public float GetCartItemsTotal()
    {
        float cartTotal = 0;
        foreach (CartEntry item in items)
        {
            cartTotal += item.GetLineItemTotal();
        }
        return cartTotal;
    }
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        return cart.GetCartItemsTotal() * (1.0f + salesTax);
    }
}

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


คุณสามารถขยายคำตอบเพื่อแนะนำการแยกส่วนเพิ่มเติมผ่านการฉีดแบบพึ่งพา (แม้ว่าคอนสตรัคเตอร์ควรจะเหมาะสมที่สุด)?
BAD_SEED

4
@Wedge ฉันเห็นเหตุผลที่ไม่ต้องมีความรู้ในการใดOrderCartการช็อปปิ้งสดและการแยกองค์ประกอบเป็นสองบริบทที่แตกต่างกัน เมื่อลูกค้าพร้อมที่จะจ่ายคุณอาจมีกระบวนการที่รับผิดชอบในการแปล CartEntries เป็นสิ่งที่ meaninful Orderสำหรับ วิธีนี้Orderชั้นก็จะ instanciated Cartและใช้งานได้โดยไม่ต้อง
plalx

@ ลิ่มคุณช่วยตอบความคิดเห็นของฉันได้ไหม?
plalx

อธิบายได้ง่าย & ดี ฉันเริ่มเห็นแสงที่ ".. แจ้งให้ทราบว่าวิธีการ OrderTotal (และระดับการสั่งซื้อ) ขึ้นอยู่กับรายละเอียดการใช้งานของ CartContents และคลาส CartEntry .. "
okey_on

ตัวอย่างนี้นำเสนออย่างชัดเจน อย่างไรก็ตามในวันนี้สถาปนิกมากขึ้นยอมรับว่าสไตล์เชิงวัตถุมากเกินไปนี้คือการปฏิบัติที่ไม่ดี มีจุดที่อยู่ในการซ่อน "การดำเนินงาน" รายละเอียดของการและCartEntry CartContentsเนื่องจากสิ่งเหล่านี้มีความหมายที่ชัดเจนอย่างสมบูรณ์แบบพวกเขาจึงควรเป็นแบบอย่างที่เป็นข้อมูลตาย ในแง่ของฐานข้อมูลทุกอย่างที่ต้องการคือตารางCREATE TABLE entry (price INTEGER, quantity INTEGER)
Jo So

160

ผลิตภัณฑ์บูรณาการจำนวนมาก (โดยเฉพาะ Apple) เช่นiPods , iPadsเป็นตัวอย่างที่ดีของการมีเพศสัมพันธ์อย่างแน่นหนา: เมื่อแบตเตอรี่ตายคุณอาจซื้ออุปกรณ์ใหม่เพราะแบตเตอรี่บัดกรีแล้วและจะไม่หลุดจึงทำให้เปลี่ยนได้อย่างมาก เเพง. ผู้เล่นคู่ที่หลวมจะอนุญาตให้เปลี่ยนแบตเตอรี่ได้อย่างง่ายดาย

การพัฒนาซอฟต์แวร์ก็เหมือนกัน: โดยทั่วไปแล้วจะดีกว่ามากหากมีโค้ดคู่กันอย่างหลวม ๆ เพื่ออำนวยความสะดวกในการขยายและแทนที่ (และทำให้แต่ละส่วนเข้าใจได้ง่ายขึ้น) แต่ไม่ค่อยมากภายใต้สถานการณ์พิเศษคับคัปปลิ้งก็มีข้อได้เปรียบเพราะการรวมกันอย่างแน่นหนาของหลายโมดูลช่วยให้การปรับให้เหมาะสมดีขึ้น


ข้อต่อหลวมหรือแน่นดี? จะตัดสินใจเลือกใช้ข้อต่อแบบหลวมหรือคลัปคับได้อย่างไร
Sreekanth Karumanaghat

2
ขอบคุณสำหรับตัวอย่างที่ดีนี้ ฉันใช้เวลามากกับคำตอบอื่น ๆ แต่ก็ไม่คุ้มค่าเช่นนี้
ลามีน

1
Sreekanth Karumanaghat คุณอยากจะใช้เงินน้อยลงสำหรับแบตเตอรี่และมี iPod ใช้งานอีกครั้งหรือคุณต้องการที่จะใช้เงินจำนวนมากสำหรับ iPod ทั้งเครื่อง?
Koshera

1
@SananthKarumanaghat โดยทั่วไปการแต่งงานกันแบบหลวม ๆ จะดีกว่าเพราะมันส่งเสริมการแยกส่วนและทำให้การบำรุงรักษาโค้ดง่ายขึ้น หากคุณจับคู่คลาส / ไลบรารี / รหัสของคุณอย่างแน่นหนาการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ ที่คุณทำในคลาสเดียวจะต้องถูกนำไปใช้ในคลาสทั้งหมดที่ใช้งาน
Kenny Worden

56

ฉันจะใช้ Java เป็นตัวอย่าง สมมติว่าเรามีคลาสที่มีลักษณะดังนี้:

public class ABC
{
   public void doDiskAccess() {...}
}

เมื่อฉันโทรหาชั้นเรียนฉันจะต้องทำสิ่งนี้:

ABC abc = new ABC();

abc. doDiskAccess();

จนถึงตอนนี้ดีมาก ตอนนี้สมมติว่าฉันมีคลาสอื่นที่มีลักษณะเช่นนี้:

public class XYZ
{
   public void doNetworkAccess() {...}
}

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

if(config.isNetwork()) new XYZ().doNetworkAccess();
else new ABC().doDiskAccess();

ใช้งานได้ แต่มันค่อนข้างเทอะทะ ฉันสามารถทำให้มันง่ายขึ้นด้วยอินเทอร์เฟซเช่นนี้:

public interface Runnable
{
    public void run();
}

public class ABC implements Runnable
{
   public void run() {...}
}

public class XYZ implements Runnable
{
   public void run() {...}
}

ตอนนี้รหัสของฉันมีลักษณะเช่นนี้:

Runnable obj = config.isNetwork() ? new XYZ() : new ABC();

obj.run();

มาดูกันว่าสะอาดกว่าและเข้าใจง่ายกว่านั้นคืออะไร? เราเพิ่งเข้าใจหลักการพื้นฐานแรกของการแต่งงานกันอย่างหลวม ๆ คีย์จากที่นี่คือเพื่อให้แน่ใจว่า ABC และ XYZ ไม่ได้ขึ้นอยู่กับวิธีการหรือตัวแปรใด ๆ ของคลาสที่เรียกพวกเขา ที่ช่วยให้ ABC และ XYZ เป็น API อิสระอย่างสมบูรณ์ หรือในคำอื่น ๆ พวกเขา "decoupled" หรือ "คู่อย่างอิสระ" จากชั้นผู้ปกครอง

แต่ถ้าเราต้องการการสื่อสารระหว่างคนทั้งสองล่ะ ถ้าอย่างนั้นเราสามารถใช้ abstractions เพิ่มเติมเช่นEvent Modelเพื่อให้แน่ใจว่าโค้ดผู้ปกครองไม่จำเป็นต้องจับคู่กับ API ที่คุณสร้างขึ้น


2
ตัวอย่างนี้ยังคงมีข้อต่อในระดับที่ค่อนข้างสูง ตอนนี้แทนที่จะเป็นคู่กับคลาสเดียวมีสองให้เลือก ตัวอย่างนี้ถือว่ามีการใช้งาน "Runnable" เพียงสองครั้งเท่านั้น ในกรณีนี้อินเทอร์เฟซไม่จำเป็นแม้แต่
โอเว่น

วิธีที่มีชื่อ Run * และ Do * เหล่านี้เป็นกลิ่นรหัสที่ยิ่งใหญ่สำหรับฉัน คุณอาจต้องปรับใช้สิ่งนี้เพื่อใช้ IHandleStuff หรือ IFrobnicateThings Runnable อยู่ไกลมากเกินไปคำทั่วไปในกรณีนี้
ลิ่ม

8
โอเว่นที่รักก้าวเท้าเพื่อนของฉัน ถ้าเขาไม่เข้าใจการแต่งงานเขาจะเข้าใจว่ารูปแบบโรงงานซื้อเขาได้อย่างไร ตัวอย่างโค้ดนี้ทำให้เขาอยู่ในเส้นทางที่ถูกต้อง ความตั้งใจคือเขาจะเข้าใจปัญหาได้ดีขึ้นและตระหนักถึงวิธีการสร้างวัตถุที่เป็นนามธรรม
64BitBob

6
นี้จะสามารถอ่านได้มากขึ้นถ้าเอบีซีและ XYZ เปลี่ยนเป็นสิ่งที่ชอบDiskAccessorและNetworkAccessor? ฉันไม่ทราบจาวา ...
MusiGenesis

มันใช้รูปแบบการออกแบบจากโรงงานหรือไม่? เพราะเรากำลังสร้างวัตถุ XYZ หรือ ABC ใหม่ขึ้นอยู่กับความต้องการ
munmunbb

37

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

การมีเพศสัมพันธ์แบบหลวม ๆ นั้นหมายความว่าองค์ประกอบการออกแบบส่วนบุคคลควรสร้างขึ้นดังนั้นจำนวนข้อมูลที่ไม่จำเป็นที่พวกเขาต้องรู้เกี่ยวกับองค์ประกอบการออกแบบอื่น ๆ จะลดลง

การทำงานร่วมกันสูงเป็นเหมือน "คลัปคับ" แต่การติดต่อกันที่สูงเป็นสถานะที่องค์ประกอบการออกแบบที่จำเป็นต้องรู้เกี่ยวกับกันและกันได้รับการออกแบบเพื่อให้พวกเขาทำงานร่วมกันอย่างเรียบร้อยและสวยงาม

ประเด็นก็คือองค์ประกอบการออกแบบบางอย่างควรรู้รายละเอียดเกี่ยวกับองค์ประกอบการออกแบบอื่น ๆ ดังนั้นจึงควรได้รับการออกแบบในลักษณะนั้นและไม่ตั้งใจ องค์ประกอบการออกแบบอื่น ๆ ไม่ควรทราบรายละเอียดเกี่ยวกับองค์ประกอบการออกแบบอื่น ๆ ดังนั้นจึงควรได้รับการออกแบบในลักษณะนั้นอย่างมีวัตถุประสงค์แทนที่จะสุ่ม

การนำสิ่งนี้ไปใช้เป็นแบบฝึกหัดสำหรับผู้อ่าน :)


33

รหัสคู่ที่แน่นหนาอาศัยการใช้งานที่เป็นรูปธรรม ถ้าฉันต้องการรายการสตริงในรหัสของฉันและฉันประกาศเช่นนี้ (ใน Java)

ArrayList<String> myList = new ArrayList<String>();

ถ้าอย่างนั้นฉันก็ต้องพึ่งพาการใช้ ArrayList

ถ้าฉันต้องการที่จะเปลี่ยนเป็นรหัสคู่อย่างอิสระฉันจะทำให้การอ้างอิงของฉันอินเตอร์เฟซประเภท (หรือนามธรรมอื่น ๆ )

List<String> myList = new ArrayList<String>();

สิ่งนี้ทำให้ฉันไม่สามารถเรียกวิธีการใด ๆmyListที่เฉพาะเจาะจงกับการใช้ ArrayList ฉัน จำกัด เฉพาะวิธีการที่กำหนดไว้ในส่วนต่อประสานรายการเท่านั้น หากฉันตัดสินใจในภายหลังว่าฉันต้องการ LinkedList จริงๆฉันต้องเปลี่ยนรหัสของฉันในที่เดียวซึ่งฉันสร้างรายการใหม่และไม่ได้อยู่ใน 100 แห่งที่ฉันโทรไปยังวิธี ArrayList

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


นี้แทบจะไม่ได้เกี่ยวข้องกับสิ่งที่ "เพศสัมพันธ์" จริงคือ ดูstackoverflow.com/questions/39946/coupling-and-cohesionสำหรับคำตอบที่ดี
Rogério

@Rogerio: ฉันคิดว่ามันเกี่ยวข้อง บางทีคุณอาจสับสนด้วยคำจำกัดความอื่นของ "การแต่งงานกัน" แต่คุณควรอ่านการแต่งงานกันแบบหลวมๆ "การมีเพศสัมพันธ์ที่แข็งแกร่งเกิดขึ้นเมื่อคลาสที่ขึ้นต่อกันมีตัวชี้ไปยังคลาสที่เป็นรูปธรรมโดยตรงซึ่งมีพฤติกรรมที่ต้องการ ... การมีเพศสัมพันธ์แบบหลวมเกิดขึ้นเมื่อคลาสที่ขึ้นต่อกันมีตัวชี้ไปยังอินเทอร์เฟซเท่านั้น ." ในตัวอย่างของฉันรหัสของฉันจะถูกรวมกับ ArrayList อย่างหลวม ๆ ผ่านส่วนต่อประสานรายการ
Bill the Lizard

@ การเรียกเก็บเงิน: ขอบคุณสำหรับการเชื่อมโยง แต่บทความที่ดูเหมือนว่าปลอมอย่างสมบูรณ์กับฉัน แต่ดูเหมือนว่ามันจะ "แปล" ความคิดจากโดเมนอื่น (พฤติกรรมองค์กร) ให้คำนิยามของ "การมีเพศสัมพันธ์หลวม" ที่ขัดแย้งกับคำนิยามของซอฟแวร์ที่เฉพาะเจาะจงเดิมโดยแลร์รีคอนสแตนติ A: en.wikipedia.org/wiki/Coupling_(computer_science)
Rogério

@Rogerio: บทความของ Constantine ถูกเขียนในปี 1974 มีความเป็นไปได้ที่การตีความซ้ำจำนวนมากได้ดำเนินไปในช่วง 36 ปีที่ผ่านมา แต่ฉันไม่คิดว่าบทความ Wikipedia เป็นแหล่งของมัน ตัวอย่างเช่นรูปแบบเช่นการพึ่งพาการพึ่งพาอาศัยอินเตอร์เฟสเพื่อคลายการมีเพศสัมพันธ์เช่นเดียวกับที่ฉันอธิบายในคำตอบของฉัน
Bill the Lizard

2
@ การเรียกเก็บเงิน: แน่นอนงานของคอนสแตนตินเกี่ยวกับการออกแบบโครงสร้างเป็นสิ่งเก่า แต่ฉันล้มเหลวที่จะเห็นเหตุผลใด ๆ ในการทำให้เป็นโมฆะหรือตีความใหม่อย่างรุนแรง แนวคิดดั้งเดิมของการทำงานร่วมกันและการมีเพศสัมพันธ์อยู่ที่แกนกลางของการออกแบบเชิงวัตถุเช่นเดียวกับมรดกและความหลากหลาย DI (บทความที่ดีกว่าคือmartinfowler.com/articles/inject.html ) เป็นเพียงเทคนิคสำหรับการกำหนดค่าภายนอกของปลั๊กอิน (อินเทอร์เฟซแบบนามธรรมพร้อมการนำไปใช้งานที่เลือกไว้ที่รันไทม์ผ่านรหัสการกำหนดค่า); อีกเทคนิคดังกล่าวคือรูปแบบของตัวค้นหาบริการ DI และการแต่งงานกันเป็นแนวคิดอิสระ
Rogério

27

ระดับความแตกต่างระหว่างคำตอบที่นี่แสดงให้เห็นว่าทำไมมันจึงเป็นแนวคิดที่ยากที่จะเข้าใจ แต่เพื่อให้ง่ายเหมือนที่ฉันสามารถอธิบายได้

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

ด้วยภาษาที่ไม่ใช่ไดนามิกเช่น c # หรือ Java เป็นต้นเราสามารถทำสิ่งนี้ผ่านอินเทอร์เฟซ ดังนั้นสมมติว่าเรามีอินเทอร์เฟซต่อไปนี้:

public ICatcher
{
   public void Catch();
}

และตอนนี้สมมติว่าเรามีคลาสดังต่อไปนี้:

public CatcherA : ICatcher
{
   public void Catch()
   {
      console.writeline("You Caught it");
   }

}
public CatcherB : ICatcher
{
   public void Catch()
   {
      console.writeline("Your brother Caught it");
   }

}

ขณะนี้ทั้ง CatcherA และ CatcherB ใช้วิธี Catch ดังนั้นบริการที่ต้องการ Catcher สามารถใช้อย่างใดอย่างหนึ่งเหล่านี้และไม่ให้แช่งที่จริง ดังนั้นการบริการที่เชื่อมโยงกันอย่างแน่นหนาอาจจะติดตั้งเช่นจับโดยตรง

public CatchService
{
   private CatcherA catcher = new CatcherA();

   public void CatchService()
   {
      catcher.Catch();
   }

}

ดังนั้น CatchService อาจทำสิ่งที่กำหนดไว้ แต่จะใช้ CatcherA และจะเป็นผู้ใช้ CatcherA เสมอ มันยากในการเข้ารหัสดังนั้นมันอยู่ที่นั่นจนกว่าจะมีใครบางคนมาและ refactors มัน

ตอนนี้ให้ใช้ตัวเลือกอื่นที่เรียกว่าการฉีดพึ่งพา:

public CatchService
{
   private ICatcher catcher;

   public void CatchService(ICatcher catcher)
   {
      this.catcher = catcher;
      catcher.Catch();
   }
}

ดังนั้น calss ที่ติดตั้ง CatchService อาจทำสิ่งต่อไปนี้:

CatchService catchService = new CatchService(new CatcherA());

หรือ

CatchService catchService = new CatchService(new CatcherB());

ซึ่งหมายความว่าบริการ Catch ไม่ได้เชื่อมต่ออย่างแน่นหนากับ CatcherA หรือ CatcherB

มีอีกหลายกลยุทธ์สำหรับบริการคลัปเช่นการใช้เฟรมเวิร์ก IoC เป็นต้น


1
ฉันชอบตัวอย่างนี้ดีกว่าอันอื่นเพราะสิ่งนี้เกิดขึ้นในโลกธุรกิจในแต่ละวัน ถ้า Class Person ทำงาน, Class Cat ทำงาน, Class Dog ทำงานเป็นต้นมันจะเป็นโปรแกรมขนาดใหญ่ที่ให้รายละเอียดของคลาสทั้งหมดที่ทำงาน แต่การใช้อินเทอร์เฟซที่เรียกว่ารันซึ่งแต่ละคลาสทำสิ่งเดียวกันทำให้โปรแกรมของคุณมีความยืดหยุ่นและจัดการได้มากขึ้น :)
sksallaj

ท่านอธิบายได้ดีจริงๆเพียงเพื่อให้ชัดเจนในตัวอย่างสุดท้ายที่คุณทำมันด้วยการฉีดพึ่งพาและตัวอย่างแรกก็ยังเป็นคู่อย่างอิสระ?
Ali Sajid

ว้าวคำตอบเก่าแสดงความคิดเห็น :) ดังนั้นคำตอบคือไม่ตัวอย่างแรกมีการพึ่งพา CatcherA อย่างหนักดังนั้นพวกเขาจึงมีการเชื่อมโยงอย่างมาก
โอเว่น

23

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


1
ดังนั้น "คู่ที่หลวม" จริงๆแล้วหมายถึงการพึ่งพาน้อยลง? ฉันถูกไหม?
user314362

4
มันไม่เกี่ยวข้องกับจำนวนการอ้างอิงทั้งหมดที่ชั้นหนึ่งมี การมีเพศสัมพันธ์ (คับหรือหลวม) เป็นคุณสมบัติของความสัมพันธ์ระหว่างสองคลาส ดังนั้นคุณอาจมีคลาสหนึ่งซึ่งมีการเชื่อมต่อกับคลาสอื่น ๆ อีก 100 คลาสหรือคลาสอื่นที่อยู่ติดกันอย่างแน่นกับคลาสอื่นเพียง 2 คลาส (ตัวอย่าง)
MusiGenesis

2
ตัวอย่างที่ไม่ดีฉันจะพูดว่า: สิ่งที่คุณมีคือการทำสำเนารหัสไม่ใช่การมีเพศสัมพันธ์อย่างแน่นหนา และด้วยเครื่องมือการรีแฟคเตอร์ที่ดีการทำซ้ำดังกล่าวสามารถกำจัดได้ในไม่กี่วินาที
Rogério

@Rogerio: อาจไม่ใช่ตัวอย่างที่ดีที่สุด ฉันชอบ64BitBobคำตอบที่ดีกว่าตัวฉันเอง
MusiGenesis

12

คำนิยาม

โดยพื้นฐานแล้วการมีเพศสัมพันธ์คือวัตถุหรือชุดของวัตถุที่กำหนดขึ้นอยู่กับวัตถุอื่นหรือชุดของวัตถุอื่นเพื่อให้งานสำเร็จ

คลัปสูง

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

คลัปหลวม

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


7

มันเป็นแนวคิดที่ค่อนข้างธรรมดาดังนั้นตัวอย่างโค้ดจะไม่ให้ภาพรวมทั้งหมด

ผู้ชายคนหนึ่งที่ทำงานที่นี่พูดกับฉันว่า "รูปแบบเหมือนเศษส่วนคุณสามารถเห็นพวกเขาเมื่อคุณซูมเข้าใกล้จริงๆและเมื่อคุณซูมเข้าใกล้ระดับสถาปัตยกรรม"

การอ่านหน้าวิกิพีเดียสั้น ๆ สามารถให้ความรู้สึกทั่วไปกับคุณได้:

http://en.wikipedia.org/wiki/Loose_coupling

เท่าที่เป็นตัวอย่างรหัสเฉพาะ ...

นี่คือข้อต่อหนึ่งที่ฉันได้ทำงานกับเมื่อเร็ว ๆ นี้จาก Microsoft.Practices.CompositeUI

    [ServiceDependency]
    public ICustomizableGridService CustomizableGridService
    {
        protected get { return _customizableGridService; }
        set { _customizableGridService = value; }
    }

รหัสนี้จะประกาศว่าชั้นนี้มีการพึ่งพาใน CustomizableGridService แทนที่จะอ้างถึงการใช้บริการที่ถูกต้องโดยตรงเพียงแค่ระบุว่าต้องมีการใช้งานบริการบางอย่าง จากนั้นที่รันไทม์ระบบจะแก้ไขการขึ้นต่อกันนั้น

หากยังไม่ชัดเจนคุณสามารถอ่านคำอธิบายโดยละเอียดเพิ่มเติมได้ที่นี่:

http://en.wikipedia.org/wiki/Dependency_injection

ลองนึกภาพว่า ABCCustomizableGridService เป็นสิ่งที่ฉันตั้งใจจะขอขึ้นที่นี่

ถ้าฉันเลือกฉันสามารถดึงมันออกมาและแทนที่ด้วย XYZCustomizableGridService หรือ StubCustomizableGridService โดยไม่มีการเปลี่ยนแปลงใด ๆ กับคลาสด้วยการขึ้นต่อกันนี้

ถ้าฉันอ้างถึง ABCCustomizableGridService โดยตรงฉันจะต้องทำการเปลี่ยนแปลงกับ / การอ้างอิงเหล่านั้นเพื่อแลกเปลี่ยนในการใช้บริการอื่น


6

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

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

ตัวอย่างบางส่วน:

  • แอปพลิเคชันขึ้นอยู่กับห้องสมุด ภายใต้คลัปแน่นแอปจะแตกรุ่นที่ใหม่กว่าของ lib Google สำหรับ "DLL Hell"

  • แอปไคลเอ็นต์อ่านข้อมูลจากเซิร์ฟเวอร์ ภายใต้คลัปแน่นการเปลี่ยนแปลงไปยังเซิร์ฟเวอร์ต้องการการแก้ไขในฝั่งไคลเอ็นต์

  • สองคลาสมีปฏิสัมพันธ์ในลำดับชั้นแบบ Object-Oriented ภายใต้คลัปแน่นการเปลี่ยนแปลงระดับหนึ่งต้องมีคลาสอื่นเพื่อให้ตรงกับการปรับปรุง

  • เครื่องมือบรรทัดคำสั่งหลายตัวสื่อสารกันในไพพ์ หากมีการเชื่อมโยงอย่างแน่นหนาการเปลี่ยนแปลงรุ่นของเครื่องมือบรรทัดคำสั่งหนึ่งจะทำให้เกิดข้อผิดพลาดในเครื่องมือที่อ่านผลลัพธ์


5

การเชื่อมต่อหมายถึงความแตกต่างของคลาสที่เชื่อมต่อกันอย่างแน่นหนา คลาสที่มีการเชื่อมโยงคู่กันแน่นมีจำนวนของการโต้ตอบและการอ้างอิงสูง

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

Legos ของเล่นที่ SNAP ร่วมกันนั้นจะถูกพิจารณาร่วมกันอย่างหลวม ๆ เพราะคุณสามารถรวบรวมชิ้นส่วนเข้าด้วยกันและสร้างระบบที่คุณต้องการ อย่างไรก็ตามตัวต่อมีชิ้นส่วนที่แน่นหนา คุณไม่สามารถนำชิ้นส่วนจากจิ๊กซอว์ตัวต่อ (ระบบ) และนำไปใช้กับตัวต่ออื่นได้เนื่องจากระบบ (ตัวต่อ) นั้นขึ้นอยู่กับชิ้นส่วนเฉพาะที่สร้างขึ้นเฉพาะสำหรับ "การออกแบบ" นั้นโดยเฉพาะ เลโก้นั้นถูกสร้างขึ้นในแบบที่เป็นแบบทั่วไปเพื่อที่จะสามารถใช้ในเลโก้เฮาส์ของคุณหรือเลโก้เอเลี่ยนเอเลี่ยนของฉัน

การอ้างอิง: https://megocode3.wordpress.com/2008/02/14/coupling-and-cohesion/


4

ส่วนประกอบสองอย่างมีความเชื่อมโยงกันอย่างมากเมื่อพวกเขาขึ้นอยู่กับการใช้งานที่เป็นรูปธรรมของแต่ละอื่น ๆ

สมมติว่าฉันมีรหัสนี้บางวิธีในชั้นเรียนของฉัน:

this.some_object = new SomeObject();

ตอนนี้ชั้นเรียนของฉันขึ้นอยู่กับ SomeObject และพวกเขาก็เชื่อมโยงกันอย่างมาก ในอีกทางหนึ่งสมมติว่าฉันมีวิธีการ InjectSomeObject:

void InjectSomeObject(ISomeObject so) { // note we require an interface, not concrete implementation
  this.some_object = so;
}

จากนั้นตัวอย่างแรกสามารถใช้การฉีด SomeObject สิ่งนี้มีประโยชน์ในระหว่างการทดสอบ ด้วยการทำงานปกติคุณสามารถใช้งานหนักการใช้ฐานข้อมูลการใช้เครือข่ายและอื่น ๆ ในขณะที่การทดสอบผ่านการใช้งานที่เบาและเยาะเย้ย ด้วยรหัสคู่ที่แน่นหนาคุณไม่สามารถทำได้

คุณสามารถทำให้บางส่วนของงานนี้ง่ายขึ้นโดยใช้ภาชนะบรรจุแบบพึ่งพา คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ DI ที่วิกิพีเดีย: http://en.wikipedia.org/wiki/Dependency_injection

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


3

พิจารณาแอพ Windows ด้วย FormA และ FormB FormA เป็นรูปแบบหลักและจะแสดง FormB ลองจินตนาการถึง FormB ที่ต้องการส่งผ่านข้อมูลกลับไปยังพาเรนต์

หากคุณทำสิ่งนี้:

class FormA 
{
    FormB fb = new FormB( this );

    ...
    fb.Show();
}

class FormB 
{
    FormA parent;

    public FormB( FormA parent )
    {
        this.parent = parent;
    }     
}

FormB เชื่อมต่อกับ FormA อย่างแน่นหนา FormB สามารถไม่มีพาเรนต์อื่นนอกจากชนิด FormA

หากในอีกทางหนึ่งคุณมี FormB เผยแพร่กิจกรรมและสมัคร FormA กับเหตุการณ์นั้น FormB สามารถส่งข้อมูลกลับผ่านเหตุการณ์นั้นไปยังสมาชิกที่มีเหตุการณ์นั้น ในกรณีนี้ FormB ไม่รู้จักการพูดกลับกับผู้ปกครอง ผ่านการมีเพศสัมพันธ์อย่างหลวม ๆ เหตุการณ์ให้มันเป็นเพียงการพูดคุยกับสมาชิก ชนิดใดก็ได้ที่สามารถเป็นแม่ของ FormA

RP


3

ในวิทยาการคอมพิวเตอร์มีความหมายอีกอย่างสำหรับ "การแต่งงานกันอย่างหลวม ๆ " ที่ไม่มีใครโพสต์เกี่ยวกับที่นี่ดังนั้น ... ไปเลย - หวังว่าคุณจะให้คะแนนฉันบ้าง แน่นอนว่าหัวเรื่องของคำตอบของฉันอยู่ในคำตอบที่ครอบคลุมทุกคำถาม ...

คำว่า "Loose Coupling" เข้าสู่การคำนวณครั้งแรกเป็นคำที่ใช้เป็นคำคุณศัพท์เกี่ยวกับสถาปัตยกรรม CPU ในการกำหนดค่าหลาย CPU คำที่เหมือนกันคือ "คลัปแน่น" Loose Coupling คือเมื่อ CPU ไม่ได้แชร์ทรัพยากรจำนวนมากร่วมกันและ Tight Coupling คือเมื่อพวกเขาทำ

คำว่า "ระบบ" อาจทำให้สับสนได้ที่นี่ดังนั้นโปรดวิเคราะห์สถานการณ์ให้ดี

โดยปกติแล้ว แต่ไม่เสมอไปซีพียูหลายตัวในการกำหนดค่าฮาร์ดแวร์ที่มีอยู่ภายในระบบเดียว (เช่นเดียวกับในกล่อง "พีซี" แต่ละอัน) จะถูกผนวกเข้าด้วยกันอย่างแน่นหนา ด้วยข้อยกเว้นของระบบที่มีประสิทธิภาพสูงพิเศษบางระบบที่มีระบบย่อยที่ใช้หน่วยความจำหลักร่วมกันระหว่าง "ระบบ" ระบบแบ่งออกได้ทั้งหมดจะถูกผนวกเข้าด้วยกันอย่างหลวม ๆ

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

ครั้งแรกเนื่องจากเป็นคำถามที่เกี่ยวกับตัวอย่างบางส่วนของระบบ Loosely Coupling:

  • VaxClusters
  • Linux Clusters

ในทางตรงกันข้ามตัวอย่างที่มีการเชื่อมต่ออย่างแน่นหนา:

  • ระบบปฏิบัติการ Semetrical-Multi-Processing (SMP) - เช่น Fedora 9
  • ซีพียูแบบมัลติเธรด
  • ซีพียูแบบ Multi-Core

ในการคำนวณของวันนี้ตัวอย่างของการปฏิบัติการทั้งสองในระบบโดยรวมเดียวไม่ใช่เรื่องแปลก ตัวอย่างเช่นใช้ซีพียู Pentium ดูอัลคอร์หรือควอดคอร์ที่ทันสมัยซึ่งใช้งาน Fedora 9 ซึ่งเป็นระบบการประมวลผลที่ผสานกันอย่างแน่นหนา จากนั้นให้รวมหลาย ๆ อย่างเข้าด้วยกันใน Linux Cluster และคุณจะมีทั้งการคำนวณแบบคู่และแบบแน่น! โอ้ฮาร์ดแวร์ทันสมัยไม่ได้ยอดเยี่ยม!


3

ในภาษาที่เรียบง่ายการรวมตัวกันอย่างหลวม ๆ หมายความว่ามันไม่ได้ขึ้นอยู่กับเหตุการณ์อื่นที่จะเกิดขึ้น มันดำเนินการอย่างอิสระ


1
นั่นไม่เป็นความจริง - ตามที่กล่าวไว้ในตัวอย่างอื่น ๆ มันไม่ได้เกี่ยวกับว่ามีความสัมพันธ์ระหว่างเอนทิตี (โมดูลคลาส) หรือไม่ แต่พวกเขาสามารถสลับได้อย่างง่ายดายหรือไม่สำหรับคลาสอื่น ๆ ที่ใช้ฟังก์ชันเดียวกัน เช่น ViewModel อาจใช้งานได้กับรุ่นที่แตกต่างกัน แต่แน่นอนว่ามันจะไม่ทำงานหากไม่มีใคร
Hayden Crocker

เอ๊ะไม่ค่อยมีประโยชน์
brgs

2

คำตอบยาว ๆ ที่นี่ หลักการง่ายมากแม้ว่า ฉันส่งข้อความเปิดจากวิกิพีเดีย :

"การแต่งงานกันแบบหลวม ๆ อธิบายความสัมพันธ์ที่ยืดหยุ่นระหว่างระบบหรือองค์กรสองแห่งหรือมากกว่าที่มีความสัมพันธ์การแลกเปลี่ยนบางอย่าง

การทำธุรกรรมในแต่ละด้านจะทำให้ข้อกำหนดนั้นชัดเจนและทำให้มีข้อสมมติฐานเล็กน้อยเกี่ยวกับส่วนอื่น ๆ "


1
ถ้ามันง่ายมากเราคงไม่มีการสนทนานี้
brgs

2

ฉันเสนอการทดสอบการเชื่อมโยงรหัสอย่างง่ายมาก:

  1. รหัสของชิ้น A นั้นถูกผนวกเข้ากับรหัสชิ้น B อย่างแน่นหนาหากมีการดัดแปลงใด ๆ ที่เป็นไปได้ของชิ้นส่วน B ที่จะบังคับให้มีการเปลี่ยนแปลงในส่วน A เพื่อรักษาความถูกต้อง

  2. โค้ดของชิ้น A นั้นไม่ได้อยู่คู่กับรหัสชิ้น B อย่างแน่นหนาหากไม่มีความเป็นไปได้ในการปรับเปลี่ยนชิ้นส่วน B ที่จะทำการเปลี่ยนเป็นส่วนที่จำเป็น

วิธีนี้จะช่วยคุณในการตรวจสอบว่ามีการเชื่อมต่อระหว่างชิ้นส่วนของรหัสของคุณมากน้อยเพียงใด สำหรับเหตุผลที่เห็นโพสต์บล็อกนี้: http://marekdec.wordpress.com/2012/11/14/loose-coupling-tight-coupling-decoupling-what-is-that-all-about/


2

เมื่อคุณสร้างออบเจ็กต์ของคลาสโดยใช้newคีย์เวิร์ดในคลาสอื่นคุณกำลังทำการคลัปแน่น (การปฏิบัติที่ไม่ดี) แทนคุณควรใช้คัปปลิ้งแบบหลวมซึ่งเป็นแนวปฏิบัติที่ดี

--- A.java ---

package interface_package.loose_coupling;

public class A {

void display(InterfaceClass obji)
{
    obji.display();
    System.out.println(obji.getVar());
}
}

--- B.java ---

package interface_package.loose_coupling;

public class B implements InterfaceClass{

private String var="variable Interface";

public String getVar() {
    return var;
}

public void setVar(String var) {
    this.var = var;
}

@Override
public void display() {
    // TODO Auto-generated method stub
    System.out.println("Display Method Called");
}
}

--- InterfaceClass ---

package interface_package.loose_coupling;

public interface InterfaceClass {

void display();
String getVar();
}

--- MainClass ---

package interface_package.loose_coupling;

public class MainClass {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    A obja=new A();
    B objb=new B();
    obja.display(objb);     //Calling display of A class with object of B class 

}
}

คำอธิบาย:

ในตัวอย่างด้านบนเรามีสองคลาส A และ B

คลาส B ใช้อินเตอร์เฟสเช่น InterfaceClass

InterfaceClass กำหนดสัญญาสำหรับคลาส B เป็น InterfaceClass มีวิธีนามธรรมของคลาส B ที่สามารถเข้าถึงได้โดยคลาสอื่นเช่น A

ในคลาส A เรามีวิธีการแสดงผลที่สามารถยกเว้นวัตถุของคลาสที่ใช้ InterfaceClass (ในกรณีของเราคือคลาส B) และในวิธีการที่วัตถุของคลาส A กำลังเรียก display () และ getVar () ของ class B

ใน MainClass เราได้สร้างวัตถุของ Class A และ B และการเรียกวิธีการแสดงผลของ A โดยผ่านวัตถุของคลาส B คือ objb แสดงวิธีการของ A จะถูกเรียกด้วยวัตถุของคลาส B

ตอนนี้พูดถึงการมีเพศสัมพันธ์หลวม สมมติว่าในอนาคตคุณต้องเปลี่ยนชื่อ Class B เป็น ABC จากนั้นคุณไม่จำเป็นต้องเปลี่ยนชื่อในวิธีการแสดงผลของคลาส B เพียงแค่สร้างออบเจ็กต์ใหม่ (คลาส ABC) และส่งต่อไปยังวิธีการแสดงผลใน MailClass คุณไม่จำเป็นต้องเปลี่ยนแปลงอะไรในคลาส A

อ้างอิง: http://p3lang.com/2013/06/loose-coupling-example-using-interface/


0

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับแนวคิดทั่วไปของ"การมีเพศสัมพันธ์หลวม"

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


-8

โดยทั่วไปการแต่งงานกันแบบหลวม ๆ เป็นนักแสดง 2 คนที่ทำงานเป็นอิสระจากกันในปริมาณงานเดียวกัน ดังนั้นถ้าคุณมีเว็บเซิร์ฟเวอร์ 2 เครื่องโดยใช้ฐานข้อมูลส่วนหลังเดียวกันคุณก็จะบอกว่าเว็บเซิร์ฟเวอร์เหล่านั้นมีการเชื่อมโยงกันอย่างหลวม ๆ คับปลิ้งคับจะถูกยกตัวอย่างโดยการมีโปรเซสเซอร์ 2 ตัวบนเว็บเซิร์ฟเวอร์เดียว ... โปรเซสเซอร์เหล่านั้นเชื่อมต่อกันอย่างแน่นหนา

หวังว่าจะเป็นประโยชน์บ้าง


1
ฉันเห็นสิ่งที่คุณกำลังจะทำ แต่ก็ยังไม่เป็นวิธีที่ดีมากในการอธิบายว่าคู่ที่แน่นหนาคือเมื่อสิ่ง 'สองสิ่ง' เป็นสิ่งที่พึ่งพาซึ่งกันและกันเมื่อเทียบกับคู่ที่หลวมเมื่อสองสิ่งต่าง ๆ มีอยู่อย่างอิสระ จะมีการเปลี่ยนแปลงได้โดยไม่ต้องมีการเปลี่ยนแปลงไป 'สิ่ง' อื่น ๆ ...
ไบรอัน Rehbein

Steve คุณพูดถูก - คุณไม่สมควรได้รับคะแนนโหวตใด ๆ มันเป็นเพียงแค่ผู้ชมของคุณยังไม่พร้อมสำหรับคำศัพท์ของคุณและมากเกินไปในเว็บไซต์นี้มีนิสัยในการออกเสียงลงคะแนนสิ่งที่พวกเขาไม่เข้าใจหรือสิ่งที่ไม่คุ้นเคย -shrug-
Richard T

ฉันคิดว่าสตีฟพลาดประเด็นไป การมีเพศสัมพันธ์แบบหลวม ๆ ไม่ได้แปลว่านักแสดง 2 คนที่ทำงานอย่างอิสระในปริมาณงานเดียวกัน
Rob
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.