ลดความซับซ้อนของคลาส


10

ฉันได้ดูคำตอบและค้นหาใน Google แล้ว แต่ฉันไม่พบสิ่งที่เป็นประโยชน์ (เช่นนั่นจะไม่มีผลข้างเคียงที่น่าอึดอัดใจ)

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

ผมเชื่อว่าวัตถุเหล่านี้จะเรียกว่าวิธีวัตถุ

ดังนั้นในตัวอย่างนี้ในบางครั้งฉันจะมี CarWithoutUpholstery ซึ่งฉันจะต้องเรียกใช้ installBackSeat, installFrontSeat, installWoodenInserts (การดำเนินการไม่รบกวนซึ่งกันและกันและอาจทำได้ในแบบคู่ขนาน) การดำเนินการเหล่านี้ดำเนินการโดย CarWithoutUpholstery.worker () และให้ผลลัพธ์เป็นวัตถุใหม่ซึ่งจะเป็น CarWithUpholstery ซึ่งฉันจะเรียกใช้ cleanInsides (), validNoUpholsteryDefects () และอื่น ๆ

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

ตรรกะของฉันในปัจจุบันใช้ Reflection เพื่อความง่ายในการใช้งาน

นั่นคือเมื่อฉันมี CarWithoutUpholstery วัตถุจะตรวจสอบตัวเองสำหรับวิธีที่เรียกว่า performSomething () ณ จุดนั้นมันรันวิธีการเหล่านี้ทั้งหมด:

myObject.perform001SomeOperation();
myObject.perform002SomeOtherOperation();
...

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

ตัวอย่างที่แตกต่าง

ให้เราบอกว่าแทนการสร้างรถผมต้องรวบรวมรายงานตำรวจลับเกี่ยวกับใครสักคนและส่งไปยังของฉันชั่วร้ายนเรศวร วัตถุสุดท้ายของฉันคือ ReadyReport เพื่อสร้างมันฉันเริ่มต้นด้วยการรวบรวมข้อมูลพื้นฐาน (ชื่อนามสกุลคู่สมรส ... ) นี่คือระยะของฉัน A. ขึ้นอยู่กับว่ามีคู่สมรสหรือไม่ฉันอาจต้องดำเนินการขั้นตอนที่ B1 หรือ B2 และรวบรวมข้อมูลเรื่องเพศในหนึ่งหรือสองคน สิ่งนี้ทำจากข้อความค้นหาที่แตกต่างกันหลายอย่างสำหรับ Evil Minions ที่แตกต่างกันในการควบคุมชีวิตกลางคืน, กล้องวงจรปิด, ใบเสร็จรับเงินจากร้านขายเซ็กซ์และสิ่งที่ไม่ และอื่น ๆ และอื่น ๆ.

หากเหยื่อไม่มีครอบครัวฉันจะไม่เข้าสู่ขั้นตอน GetInformationAboutFamily แต่ถ้าฉันทำมันก็ไม่เกี่ยวข้องเลยว่าฉันจะกำหนดเป้าหมายไปที่พ่อหรือแม่หรือพี่น้อง (ถ้ามี) ก่อน แต่ฉันไม่สามารถทำเช่นนั้นได้หากฉันไม่ได้ทำ FamilyStatusCheck ซึ่งเป็นของเฟสก่อนหน้า

มันทำงานได้อย่างยอดเยี่ยม ...

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

...แต่...

ปัญหาเกิดขึ้นเมื่อฉันเพิ่มการดำเนินการครั้งสุดท้ายหนึ่งในวัตถุวิธีหนึ่งของฉันซึ่งทำให้โมดูลโดยรวมเกินดัชนีความซับซ้อนบังคับ ("น้อยกว่าวิธีส่วนตัว N")

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

จากการใช้ตัวอย่าง Evil Overlord ปัญหาของฉันคือ Evil Overlord (หรือผู้ที่ไม่ถูกปฏิเสธ ) ที่ได้รับการร้องขอข้อมูลด้านโภชนาการทั้งหมด Minions การกินของฉันบอกฉันว่าฉันต้องการสอบถามร้านอาหารครัวเล็ก ๆ ผู้ค้าริมถนนผู้ขายที่ไม่มีใบอนุญาต เจ้าของ ฯลฯ และความชั่วร้าย (ย่อย) นเรศวร - รู้จักกันดีในนามเขาผู้ซึ่งไม่ควรถูกปฏิเสธ - บ่นว่าฉันแสดงข้อความค้นหามากเกินไปในระยะ GetDietaryInformation

หมายเหตุ : ฉันทราบว่าในหลาย ๆ มุมมองนี่ไม่ใช่ปัญหาเลย (ไม่สนใจปัญหาประสิทธิภาพที่เป็นไปได้ ฯลฯ ) สิ่งที่เกิดขึ้นคือตัวชี้วัดเฉพาะไม่มีความสุขและมีเหตุผลสำหรับสิ่งนั้น

สิ่งที่ฉันคิดว่าฉันสามารถทำได้

นอกเหนือจากข้อแรกตัวเลือกทั้งหมดเหล่านี้สามารถทำได้และฉันคิดว่าสามารถป้องกันได้

  • protectedฉันได้ยืนยันว่าผมสามารถส่อเสียดและประกาศครึ่งหนึ่งวิธีของฉัน แต่ฉันจะใช้ประโยชน์จากจุดอ่อนในกระบวนการทดสอบและนอกเหนือจากการพิสูจน์ตัวเองเมื่อถูกจับฉันไม่ชอบสิ่งนี้ นอกจากนี้ยังเป็นมาตรการชั่วคราว เกิดอะไรขึ้นถ้าจำนวนของการดำเนินการที่ต้องการเป็นสองเท่า? ไม่แน่ แต่แล้วจะเป็นอย่างไร
  • ฉันสามารถแยกเฟสนี้โดยพลการเป็น AnnealedObjectAlpha, AnnealedObjectBravo และ AnnealedObjectCharlie และมีหนึ่งในสามของการดำเนินการที่ดำเนินการในแต่ละขั้นตอน ฉันอยู่ภายใต้ความประทับใจที่จริง ๆ แล้วเพิ่มความซับซ้อน (คลาสเพิ่มเติม N-1) โดยไม่มีประโยชน์ยกเว้นการผ่านการทดสอบ แน่นอนฉันสามารถถือได้ว่า CarWithFrontSeatsInstalled และ CarWithAllSeatsInstalled เป็นขั้นตอนต่อเนื่องเชิงตรรกะ ความเสี่ยงของวิธีการ Bravo ที่ Alpha จำเป็นต้องใช้ในภายหลังนั้นมีขนาดเล็กและเล็กลงถ้าฉันเล่นได้ดี แต่ยังคง.
  • ฉันสามารถมัดการทำงานที่แตกต่างกันคล้ายกันจากระยะไกลในหนึ่งเดียว performAllSeatsInstallation(). นี่เป็นเพียงมาตรการชั่วคราวและเพิ่มความซับซ้อนของการดำเนินการเดียว หากฉันต้องการดำเนินการ A และ B ตามลำดับที่แตกต่างกันและฉันได้บรรจุไว้ใน E = (A + C) และ F (B + D) ฉันจะต้องแยก E และ F และสลับรหัสรอบ ๆ .
  • ฉันสามารถใช้ฟังก์ชั่นแลมบ์ดาได้หลายอย่างและเลี่ยงขั้นตอนการตรวจสอบโดยสิ้นเชิง แต่ฉันพบว่ามันเป็น clunky อย่างไรก็ตามนี่เป็นทางเลือกที่ดีที่สุดจนถึงปัจจุบัน มันจะกำจัดการสะท้อนกลับ ปัญหาสองอย่างที่ฉันมีคือฉันอาจจะถูกขอให้เขียนวัตถุวิธีการทั้งหมดไม่เพียง แต่สมมุติCarWithEngineInstalledและในขณะที่จะรักษาความปลอดภัยงานที่ดีมากมันไม่ได้ดึงดูดมาก และตัวตรวจสอบรหัสครอบคลุมมีปัญหากับ lambdas (ซึ่งแก้ไขได้ แต่ยังคงอยู่ )

ดังนั้น...

  • คุณคิดว่าตัวเลือกที่ดีที่สุดของฉันคืออะไร?
  • มีวิธีที่ดีกว่าที่ฉันไม่ได้พิจารณาหรือไม่? ( บางทีฉันควรจะมาทำความสะอาดและถามว่ามันคืออะไร? )
  • การออกแบบนี้มีข้อบกพร่องอย่างสิ้นหวังและฉันควรยอมรับความพ่ายแพ้และคลอง - สถาปัตยกรรมนี้โดยสิ้นเชิง? ไม่ดีสำหรับอาชีพการงานของฉัน แต่การเขียนโค้ดที่ออกแบบมาไม่ดีจะดีกว่าในระยะยาวหรือไม่
  • ตัวเลือกปัจจุบันของฉันคือทางเลือกเดียวหรือไม่และฉันต้องต่อสู้เพื่อให้ได้การวัดคุณภาพที่ดีขึ้น (และ / หรือเครื่องมือ) สำหรับตัวเลือกสุดท้ายนี้ฉันจะต้องอ้างอิง ... ฉันไม่สามารถเพียงแค่คลื่นมือของฉันที่ @PHB ในขณะที่บ่นเหล่านี้ไม่ได้ชี้วัดที่คุณกำลังมองหา ไม่ว่าฉันจะอยากได้เท่าไหร่

3
หรือคุณสามารถละเว้นคำเตือน "เกินความซับซ้อนสูงสุด"
Robert Harvey

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

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

2
การปกครองแบบเผด็จการ เมทริกเป็นตัวบ่งชี้ที่มีประโยชน์ แต่การบังคับใช้ขณะที่ไม่สนใจสาเหตุที่ใช้เมตริกนั้นไม่เป็นประโยชน์
Jaydee

2
อธิบายให้คนชั้นบนเห็นความแตกต่างระหว่างความซับซ้อนที่จำเป็นและความซับซ้อนโดยไม่ตั้งใจ en.wikipedia.org/wiki/No_Silver_Bulletหากคุณแน่ใจว่าความซับซ้อนที่ทำลายกฎนั้นเป็นสิ่งจำเป็นถ้าคุณทำการปรับโครงสร้างต่อprogrammers.stackexchange.com/a/297414/51948คุณอาจเล่นสเก็ตรอบกฎและแพร่กระจาย ออกความซับซ้อน หากการห่อหุ้มสิ่งต่าง ๆ ลงในเฟสไม่ได้เป็นการกำหนดเอง (ขั้นตอนเกี่ยวข้องกับปัญหา) และการออกแบบใหม่ช่วยลดภาระการรับรู้สำหรับนักพัฒนาที่ดูแลรหัส
Fuhrmanator

คำตอบ:


15

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

ในการสร้างตัวอย่างประกอบรถยนต์ให้จินตนาการถึงCarชั้นเรียน:

public class Car
{
    public IChassis Chassis { get; private set; }
    public Dashboard { get; private set; }
    public IList<Seat> Seats { get; private set; }

    public Car()
    {
        Seats = new List<Seat>();
    }

    public void AddChassis(IChassis chassis)
    {
        Chassis = chassis;
    }

    public void AddDashboard(Dashboard dashboard)
    {
        Dashboard = dashboard;
    }
}

ฉันจะออกจากการใช้งานของบางส่วนของส่วนประกอบเช่นIChassis, SeatและDashboardเพื่อประโยชน์ของความกะทัดรัด

Carจะไม่รับผิดชอบสำหรับการสร้างตัวเอง แอสเซมบลีไลน์คือดังนั้นให้แค็ปซูลในคลาส:

public class CarAssembler
{
    protected List<IAssemblyPhase> Phases { get; private set; }

    public CarAssembler()
    {
        Phases = new List<IAssemblyPhase>()
        {
            new ChassisAssemblyPhase(),
            new DashboardAssemblyPhase(),
            new SeatAssemblyPhase()
        };
    }

    public void Assemble(Car car)
    {
        foreach (IAssemblyPhase phase in Phases)
        {
            phase.Assemble(car);
        }
    }
}

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

public interface IAssemblyPhase
{
    void Assemble(Car car);
}

ตอนนี้เราต้องการคลาสที่เป็นรูปธรรมของเราที่ใช้อินเทอร์เฟซนี้สำหรับแต่ละเฟสเฉพาะ:

public class ChassisAssemblyPhase : IAssemblyPhase
{
    public void Assemble(Car car)
    {
        car.AddChassis(new UnibodyChassis());
    }
}

public class DashboardAssemblyPhase : IAssemblyPhase
{
    public void Assemble(Car car)
    {
        Dashboard dashboard = new Dashboard();

        dashboard.AddComponent(new Speedometer());
        dashboard.AddComponent(new FuelGuage());
        dashboard.Trim = DashboardTrimType.Aluminum;

        car.AddDashboard(dashboard);
    }
}

public class SeatAssemblyPhase : IAssemblyPhase
{
    public void Assemble(Car car)
    {
        car.Seats.Add(new Seat());
        car.Seats.Add(new Seat());
        car.Seats.Add(new Seat());
        car.Seats.Add(new Seat());
    }
}

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

แม้ว่าคุณจะพูดว่าคำสั่งซื้อไม่สำคัญในตอนนี้ แต่มันอาจจะเกิดขึ้นในอนาคต

ในการทำสิ่งนี้ให้เสร็จให้ดูขั้นตอนการประกอบรถยนต์:

Car car = new Car();
CarAssembler assemblyLine = new CarAssembler();

assemblyLine.Assemble(car);

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


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

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

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

ตัวเลือกปัจจุบันของฉันคือทางเลือกเดียวหรือไม่และฉันต้องต่อสู้เพื่อให้ได้การวัดคุณภาพที่ดีขึ้น (และ / หรือเครื่องมือ)

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


1
ใช่ดีขึ้นมากแล้วมีชั้นหนึ่งพระเจ้า
BЈовић

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

@DavidPacker: แม้ว่าคุณจะต้องกำหนดค่าสิ่งต่าง ๆ มากมายคุณสามารถแค็ปซูลนั้นได้เช่นกันในคลาส Config บางประเภทที่คุณผ่านเข้าไปในตัวสร้างของวัตถุ "แอสเซมเบลอร์" ในตัวอย่างรถยนต์คันนี้สีสีสีและวัสดุภายในแพคเกจการตกแต่งเครื่องยนต์และอื่น ๆ สามารถกำหนดเองได้ แต่คุณไม่จำเป็นต้องมีการปรับแต่ง 150 แบบ คุณอาจจะมีโหลหรือมากกว่านั้นซึ่งยืมตัวเองไปที่วัตถุตัวเลือก
Greg Burghardt

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

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

1

ฉันไม่รู้ว่าสิ่งนี้เป็นไปได้สำหรับคุณหรือไม่ แต่ฉันจะคิดถึงการใช้วิธีการที่มุ่งเน้นข้อมูลมากขึ้น แนวความคิดคือคุณจับภาพบางส่วน (ประกาศ) ของกฎ & ข้อ จำกัด , การดำเนินงาน, การอ้างอิง, รัฐ, ฯลฯ ... จากนั้นชั้นเรียนและรหัสของคุณมีความทั่วไปมากขึ้นมุ่งเน้นไปที่การปฏิบัติตามกฎเริ่มต้นสถานะปัจจุบันของอินสแตนซ์ เปลี่ยนสถานะโดยใช้การจับภาพการประกาศของกฎและการเปลี่ยนแปลงสถานะแทนที่จะใช้รหัสเพิ่มเติมโดยตรง หนึ่งอาจใช้การประกาศข้อมูลในภาษาการเขียนโปรแกรมหรือเครื่องมือ DSL บางตัวหรือกฎหรือกลไกลอจิก


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

1

ยังไงก็เถอะปัญหาเตือนฉันของการอ้างอิง คุณต้องการรถยนต์ในการกำหนดค่าเฉพาะ เช่นเดียวกับ Greg Burghardt ฉันจะไปกับวัตถุ / คลาสสำหรับแต่ละขั้นตอน / รายการ / …

แต่ละขั้นตอนจะประกาศสิ่งที่มันเพิ่มลงในมิกซ์ (มันคืออะไรprovides) (อาจเป็นหลาย ๆ อย่าง) แต่ก็ต้องมีเช่นกัน

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

อัลกอริทึมการแก้ปัญหาการพึ่งพานั้นไม่ใช่เรื่องยาก กรณีที่ง่ายที่สุดคือที่แต่ละขั้นตอนให้สิ่งหนึ่งและไม่มีสองสิ่งที่ให้สิ่งเดียวกันและการอ้างอิงนั้นง่าย (ไม่มี 'หรือ' ในการพึ่งพา) สำหรับกรณีที่ซับซ้อนมากขึ้นเพียงแค่ดูเครื่องมือเช่น debian apt หรืออะไรบางอย่าง

ในที่สุดการสร้างรถของคุณก็จะลดขั้นตอนที่เป็นไปได้ลงไปและปล่อยให้ CarBuilder ค้นหาขั้นตอนที่จำเป็น

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


0

สองสิ่งที่คุณพูดถึงโดดเด่นว่า 'ไม่ดี' สำหรับฉัน

"ตรรกะของฉันใช้ Reflection เพื่อความง่ายในการใช้งาน"

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

"การดำเนินงานในเฟสเดียวมีความเป็นอิสระอยู่แล้ว"

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

MyObject.AddComponent(IComponent component) 

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

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

ในกรณีนี้คุณสามารถ:

  1. โยน OOP ออกไปนอกหน้าต่างและมีบริการที่ทำงานกับข้อมูลที่เปิดเผยในชั้นเรียนของคุณเช่น

    บริการเพิ่มลงในรถ (รถคาร์)

  2. มีคลาสผู้สร้างที่สร้างวัตถุของคุณโดยการรวบรวมข้อมูลที่จำเป็นก่อนแล้วจึงส่งกลับวัตถุที่เสร็จสมบูรณ์แล้วเช่น

    รถยนต์ = CarBuilder WithDoor (). WithDoor (). WithWheels ();

(ตรรกะ withX สามารถแบ่งออกเป็น subbuilders อีกครั้ง)

  1. ใช้ฟังก์ชั่นการใช้งานและส่งผ่านฟังก์ชั่น / แบ่งเป็นวิธีแก้ไข

    Car.Modify ((c) => c.doors ++);


Ewan กล่าวว่า: "โยน OOP ออกไปนอกหน้าต่างและมีบริการที่ทำงานกับข้อมูลที่เปิดเผยในชั้นเรียนของคุณ" --- นี่ไม่ใช่ Object-oriented หรือไม่?
Greg Burghardt

?? ไม่ใช่มันเป็นตัวเลือกที่ไม่ใช่ของ OO
Ewan

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

มัน 'ไม่ OO' เพราะคุณกำลังเปิดเผยข้อมูลราวกับว่ามันเป็น struct และปฏิบัติการกับมันในระดับที่แยกต่างหากเช่นเดียวกับในขั้นตอน
Ewan

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