การใช้อินเทอร์เฟซสำหรับการจัดหมวดหมู่เป็นเรื่องที่ผิดหรือไม่


12

ตัวอย่างเช่น:

บอกฉันได้เรียนA, ,B Cฉันมีสองอินเตอร์เฟซที่ช่วยให้เรียกพวกเขาและIAnimal สืบทอดจาก และมีs ในขณะที่ไม่ได้ แต่มันก็เป็นIDogIDogIAnimalABIDogCIAnimal

ส่วนที่สำคัญคือIDogไม่มีการใช้งานเพิ่มเติม มันใช้เพื่ออนุญาตAและBไม่Cผ่านการโต้แย้งเป็นวิธีการบางอย่าง

นี่คือการปฏิบัติที่ไม่ดีหรือไม่?


8
IAnimalและIDogเป็นชื่อซ้ำซากสาหัส!

5
@JarrodRoberson ในขณะที่ฉันเห็นด้วยถ้าคุณทำงานในโลกของ. Net คุณจะติดอยู่กับมัน (หรือจะขัดแย้งกับการประชุมที่จัดตั้งขึ้นหากคุณทำมันแตกต่างกัน)
Daniel B

2
@JarrodRoberson IMHO MyProject.Data.IAnimalและMyProject.Data.Animalดีกว่าMyProject.Data.Interfaces.Animalและ MyProject.Data.Implementations.Animal
Mike Koder

1
ประเด็นก็คือไม่ควรมีเหตุผลใด ๆ ที่จะต้องสนใจว่ามันเป็นInterfaceหรือImplementationไม่ว่าจะเป็นคำนำหน้าซ้ำหรือใน namespace อย่างใดอย่างหนึ่งก็เป็นเรื่องที่ซ้ำซากอย่างใดอย่างหนึ่งและละเมิด DRY Dogคือทั้งหมดที่คุณควรใส่ใจ PitBull extends Dogไม่ต้องการการใช้งานซ้ำซ้อนอย่างใดอย่างหนึ่งคำextendsบอกฉันทั้งหมดที่ฉันต้องรู้อ่านลิงค์ที่ฉันโพสต์ในความคิดเห็นเดิมของฉัน

1
@ Jarrod: หยุดบ่นกับฉัน ร้องเรียนกับทีมงาน. dev ถ้าฉันไปกับมาตรฐาน devs เพื่อนของฉันจะเกลียดความกล้าของฉัน
เคนดัลล์เฟรย์

คำตอบ:


13

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

ไม่ใช่แนวปฏิบัติที่ไม่ถูกต้อง แต่สามารถเปลี่ยนอินเตอร์เฟส (คุณลักษณะ) ได้หากภาษาที่คุณใช้รองรับ

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

นี่คือตัวอย่างจากโครงการออร์ชาร์ด

public interface ISingletonDependency : IDependency {}

/// <summary>
/// Base interface for services that may *only* be instantiated in a unit of work.
/// This interface is used to guarantee they are not accidentally referenced by a singleton dependency.
/// </summary>
public interface IUnitOfWorkDependency : IDependency {}

/// <summary>
/// Base interface for services that are instantiated per usage.
/// </summary>
public interface ITransientDependency : IDependency {}

โปรดดูที่เครื่องหมายอินเตอร์เฟซ


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

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

ฉันสับสน รูปแบบ 'อินเทอร์เฟซของตัวทำเครื่องหมาย' นี้มีการตรวจสอบเวลาคอมไพล์โดยที่คุณไม่สามารถส่งผ่านCไปยังวิธีการที่IDogต้องการ
เคนดัลล์เฟรย์

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

ให้ฉันอธิบายมันตามที่ฉันทำในความคิดเห็นเกี่ยวกับคำตอบของ Telastyn เช่นฉันมีKennelชั้นเรียนที่ร้านค้ารายการIDogs
เคนดัลล์เฟรย์

4

ใช่มันเป็นการปฏิบัติที่ไม่ดีในเกือบทุกภาษา

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

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

[แก้ไข: การชี้แจง]

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

บางภาษามีกลไกลักษณะที่ไม่เลวร้ายเกินไป แต่คนเหล่านั้นมักจะมุ่งเน้นไปที่ความสามารถไม่ใช่การปรับแต่ง ฉันมีประสบการณ์เล็กน้อยกับพวกเขาดังนั้นจึงไม่สามารถพูดกับแนวทางปฏิบัติที่ดีที่สุดที่นั่นได้ ใน C ++ / Java / C # แม้ว่า ... ไม่ดี


ฉันสับสนสองย่อหน้ากลางของคุณ 'sub-type' หมายถึงอะไร? ฉันกำลังใช้อินเทอร์เฟซซึ่งเป็นสัญญาไม่ใช่การนำไปใช้และฉันไม่แน่ใจว่าความคิดเห็นของคุณจะนำไปใช้อย่างไร คุณหมายถึงอะไรโดย 'ไม่พิมพ์' 'นัย' หมายถึงอะไร? IDog สามารถทำทุกอย่างที่ IAnimal สามารถทำได้ แต่ไม่รับประกันว่าจะสามารถทำอะไรได้มากกว่า
เคนดัลล์เฟรย์

ขอขอบคุณสำหรับการชี้แจง. ในกรณีเฉพาะของฉันฉันไม่ได้ใช้อินเทอร์เฟซต่างกัน มันอาจจะสามารถอธิบายได้ดีที่สุดด้วยการบอกว่าฉันมีKennelชั้นเรียนที่ร้านค้ารายการIDogs
เคนดัลล์เฟรย์

@ เคนดอลเฟรย์: ไม่ว่าคุณจะขับออกจากอินเทอร์เฟซ (ไม่ดี) หรือคุณกำลังสร้างความแตกต่างที่ประดิษฐ์ซึ่งมีกลิ่นของสิ่งที่ไม่ถูกต้อง
Telastyn

2
@Telastyn - วัตถุประสงค์ของอินเทอร์เฟซเช่นนั้นคือการให้ข้อมูลเมตา
Freshblood

1
@Telastyn: ดังนั้นคุณลักษณะจะนำไปใช้กับการตรวจสอบเวลารวบรวมได้อย่างไร AFAIK ใน C # สามารถใช้แอตทริบิวต์ได้เฉพาะขณะใช้งานจริง
เคนดัลล์เฟรย์

2

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

if(animal is IDog)
{
}
if(animal.Type == AnimalType.Dog)
{
}
if(animal.GetType().GetCustomAttributes(typeof(DogAttribute), false).Any())
{
}


var dogs1 = animals.OfType<IDog>();
var dogs2 = animals.Where(a => a.Type == AnimalType.Dog);
var dogs3 = animals.Where(a => a.GetType().GetCustomAttributes(typeof(DogAttribute), false).Any());


var dogsFromDb1 = session.Query<IDog>();
var dogsFromDb2 = session.Query<Animal>().Where(a => a.Type == AnimalType.Dog);
var dogsFromDb3 = session.Query<Animal>().Where(a => a.GetType().GetCustomAttributes(typeof(DogAttribute),false).Any());


public void DoSomething(IDog dog)
{
}
public void DoSomething(Animal animal)
{
    if(animal.Type != AnimalType.Dog)
    {
        throw new ArgumentException("This method should be used for dogs only.");
    }
}
public void DoSomething(Animal animal)
{
    if(!animal.GetType().GetCustomAttributes(typeof(DogAttribute), false).Any())
    {
        throw new ArgumentException("This method should be used for dogs only.");
    }
}

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

ฉันมีกรณีการใช้งาน simillar แต่ส่วนใหญ่. devs สุทธิแนะนำอย่างยิ่งกับมัน แต่ฉันจะไม่ใช้คุณลักษณะ
GorillaApe

-1

ไม่มีอะไรผิดปกติกับการมีอินเตอร์เฟสซึ่งสืบทอดอินเตอร์เฟสอื่นโดยไม่เพิ่มสมาชิกใหม่หากการใช้งานทั้งหมดของอินเตอร์เฟสหลังนั้นคาดว่าจะสามารถทำสิ่งที่เป็นประโยชน์ซึ่งการใช้งานบางอย่างของอดีตอาจไม่เป็นประโยชน์ แท้จริงแล้วมันเป็นรูปแบบที่ดีซึ่ง IMHO ควรใช้ในสิ่งต่าง ๆ เช่น. net Framework โดยเฉพาะอย่างยิ่งเนื่องจากผู้ใช้ที่คลาสจะมีข้อ จำกัด ตามนัยโดยอินเทอร์เฟซที่ได้รับมามากกว่านั้นสามารถบ่งชี้ว่า , โดยไม่ต้องเปลี่ยนรหัสการประกาศใช้งานหรือการประกาศใด ๆ

ตัวอย่างเช่นสมมติว่าฉันมีอินเทอร์เฟซ:

อินเตอร์เฟส IMaybeMutableFoo {
  Bar Thing {get; set;} // และคุณสมบัติอื่น ๆ เช่นกัน
  บูล IsMutable;
  IImmutableFoo AsImmutable ();
}
อินเตอร์เฟส IImmutableFoo: IMaybeMutableFoo {};

การดำเนินการของIImmutableFoo.AsImmutable()คาดว่าจะกลับมา; การใช้คลาสที่ไม่แน่นอนIMaybeMutableFoo.AsImmutable()นั้นคาดว่าจะส่งคืนออบเจ็กต์ที่เปลี่ยนแปลงไม่ได้อย่างล้ำลึกซึ่งมีสแนปช็อตของข้อมูล รูทีนที่ต้องการเก็บสแน็ปช็อตของข้อมูลที่เก็บไว้ใน a IMaybeMutableFooสามารถเสนอโอเวอร์โหลดได้:

โมฆะสาธารณะ StoreData (IImmutableFoo ThingToStore)
{
  // การจัดเก็บข้อมูลอ้างอิงจะเพียงพอเนื่องจาก ThingToStore เป็นที่รู้กันว่าไม่เปลี่ยนรูป
}
โมฆะสาธารณะ StoreData (IMaybeMutableFoo ThingToStore)
{
  StoreData (ThingToStore.AsImmutable ()); // เรียกโอเวอร์โหลดที่เจาะจงมากขึ้น
}

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


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