การนำอินเตอร์เฟซทั่วไปหลาย ๆ ตัวมาใช้ในจาวา


10

ฉันต้องการอินเทอร์เฟซที่ทำให้ฉันมั่นใจว่ามีวิธีการบางอย่างรวมถึงลายเซ็นเฉพาะ จนถึงตอนนี้เขาคือสิ่งที่ฉันมี:

public interface Mappable<M> {
    M mapTo(M mappableEntity);
}

ปัญหาเกิดขึ้นเมื่อคลาสควรแม็พกับเอนทิตีอื่น ๆ กรณีที่เหมาะสมที่สุดคือ (ไม่ใช่ java):

public class Something implements Mappable<A>, Mappable<B> {
    public A mapTo(A someObject) {...}
    public B mapTo(B someOtherObject) {...}
}

อะไรจะเป็นวิธีที่ดีที่สุดในการบรรลุถึงสิ่งที่เหลืออยู่นี้ให้เป็น "สามัญ" ที่สุด

คำตอบ:


10

นี้เป็นที่แน่นอนไม่ได้เป็นสิ่งที่คุณสามารถทำได้เนื่องจากประเภทลบ ที่รันไทม์คุณมีสองวิธีpublic Object mapTo(Object)ซึ่งเห็นได้ชัดว่าไม่สามารถอยู่ร่วมกันได้

น่าเสียดายที่สิ่งที่คุณพยายามทำนั้นอยู่นอกเหนือจากระบบพิมพ์ของจาวา

สมมติว่าประเภททั่วไปของคุณเป็นประเภทที่หนึ่งเสมอและไม่ใช่ประเภททั่วไปคุณสามารถบรรลุพฤติกรรมภายนอกที่คล้ายกันโดยมีวิธีการmapTo(Object, Class)ซึ่งจะช่วยให้คุณทำการตรวจสอบรันไทม์ของชั้นเรียนที่กำหนดและตัดสินใจว่าพฤติกรรมที่จะใช้ เห็นได้ชัดว่านี่เป็นสิ่งที่ไม่สวย - และจะต้องใช้การหล่อด้วยตนเองของค่าตอบแทน - แต่ฉันคิดว่ามันดีที่สุดที่คุณสามารถทำได้ หากประเภททั่วไปของคุณเป็นประเภททั่วไปพารามิเตอร์ทั่วไปจะถูกลบด้วยและระดับจะเท่ากันดังนั้นวิธีนี้จะไม่ทำงาน

อย่างไรก็ตามฉันจะชี้ไปที่คำตอบของ @ Joachim ด้วยซึ่งอาจเป็นกรณีที่คุณสามารถแยกพฤติกรรมออกเป็นส่วนประกอบที่แยกจากกันและหลีกเลี่ยงปัญหาทั้งหมด


3

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

นอกจากนี้วิธีการนี้ยังละเมิดหลักการความรับผิดชอบเดียว: ชั้นเรียนของคุณควรมุ่งเน้นการเป็นSomething(สิ่งที่หมายถึง) และไม่ควรทำแผนที่AหรือB นอกเหนือจากงานนั้น

ดูเหมือนคุณจริงๆควรจะมีและMapper<Something,A> Mapper<Something,B>วิธีนี้แต่ละคลาสมีความรับผิดชอบที่กำหนดไว้อย่างชัดเจนและคุณไม่พบปัญหาในการใช้อินเทอร์เฟซเดียวกันสองครั้ง


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

@estani: ใช่พวกเขาค่อนข้างแน่น แต่พวกเขามีความรับผิดชอบที่แตกต่างกัน ลองคิดถึงสิ่งนี้ด้วย: เมื่อคุณแนะนำคลาสใหม่Cและคุณต้องการที่Somethingจะแมปกับคลาสนั้นคุณจะต้องแก้ไขSomethingซึ่งเป็นข้อต่อที่มากเกินไป เพียงเพิ่มใหม่SoemthingToCMapperจะรบกวนน้อย
โจอาคิมซาวเออร์

1
+1 กับสิ่งนี้ - โดยทั่วไปแล้วคุณควรจะชอบการแต่งเพลงมากกว่าการสืบทอดถ้าคุณพยายามที่จะบรรลุสิ่งที่ OP ต้องการ (ใน Java) Java 8 ที่มีวิธีการเริ่มต้นทำให้สิ่งนี้ง่ายยิ่งขึ้น - แต่ทุกคนไม่สามารถกระโดดขึ้นไปบนขอบเลือดออกได้ :-)
Martijn Verburg

0

เนื่องจากไม่อนุญาตให้ใช้อินเทอร์เฟซหลายรายการคุณสามารถพิจารณาการใช้การห่อหุ้ม (ตัวอย่างโดยใช้ java8 +)

// Mappable.java
public interface Mappable<M> {
    M mapTo(M mappableEntity);
}

// TwoMappables.java
public interface TwoMappables {
    default Mappable<A> mapableA() {
         return new MappableA();
    }

    default Mappable<B> mapableB() {
         return new MappableB();
    }

    class MappableA implements Mappable<A> {}
    class MappableB implements Mappable<B> {}
}

// Something.java
public class Something implements TwoMappables {
    // ... business logic ...
    mapableA().mapTo(A);
    mapableB().mapTo(B);
}

โปรดตรวจสอบที่นี่สำหรับข้อมูลเพิ่มเติม & ตัวอย่างเพิ่มเติม: วิธีสร้างคลาส Java ที่ใช้หนึ่งอินเตอร์เฟสที่มีสองประเภททั่วไปได้อย่างไร .


-1
public interface IMappable<S, T> {
    T MapFrom(S source);
}

// T - target
// S - source

ถ้าคุณต้องการแมปผู้ใช้กับ UserDTO และแมปผู้ใช้กับ UserViewModel คุณจะต้องมีการใช้งานสองแบบแยกกัน อย่าวางตรรกะทั้งหมดนี้ไว้ในชั้นเรียนเดียว - มันไม่มีเหตุผลที่จะทำเช่นนั้น

อัพเดทเพื่อให้โจอาคิมมีความสุข

public interface ITypeConverter<TSource, TDestination>
{
    TDestination Convert(TSource source);
}

แต่ตอนนี้เราอยู่ในขอบเขตของ Automapper ( http://automapper.codeplex.com/wikipage?title=Custom%20Type%20Converters )


ฉันไม่คิดว่าIMappableเป็นชื่อที่ดีสำหรับสิ่งที่แมปสิ่งอื่น ๆ Mapper(หรือIMapperถ้าคุณต้อง ;-)) น่าจะถูกต้องกว่านี้ (โดยวิธี: ไม่นั่นไม่ใช่ downvote ของฉัน)
Joachim Sauer

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

1
ขอโทษ แต่ในความคิดของฉันไม่สามารถ "แก้ปัญหา" การออกแบบและละเว้นการตั้งชื่อได้ การออกแบบหมายถึงโครงสร้างที่เข้าใจได้ การตั้งชื่อผิดเป็นปัญหาที่ต้องเข้าใจ
Joachim Sauer

การอัปเดตควรคำนึงถึงเรื่องที่เหลือ ;-)
CodeART

1
@CodeART ถ้าฉันเข้าใจคำตอบของคุณถูกต้องมันหมายถึง "MapFrom" (ซึ่งควรจะลดระดับ ;-) สร้างวัตถุ ในกรณีของฉันมันเป็นเพียงการกรอกข้อมูลเกี่ยวกับวัตถุที่สร้างขึ้นแล้ว
estani
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.