2010-09-29 1 views
2

У меня есть проект, который добавляет элементы к чертежу AutoCad. Я заметил, что начал писать те же десять строк кода несколькими способами (для простоты показаны только два).«Чистый код: рекомендации по заказу на пригодность для зависимостей?

Начальная реализация: Вы заметите, что единственное, что действительно меняется, это добавление линии вместо круга.

[CommandMethod("Test", CommandFlags.Session)] 
    public void Test() 
    { 
     AddLineToDrawing(); 
     AddCircleToDrawing(); 
    } 

    private void AddLineToDrawing() 
    { 
     using (DocumentLock lockedDocument = Application.DocumentManager.MdiActiveDocument.LockDocument()) 
     { 
      using (Database database = Application.DocumentManager.MdiActiveDocument.Database) 
      { 
       using (Transaction transaction = database.TransactionManager.StartTransaction())//Start the transaction 
       { 
        //Open the block table for read 
        BlockTable blockTable = transaction.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable; 

        //Open the block table record model space for write 
        BlockTableRecord blockTableRecord = (BlockTableRecord)transaction.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite); 

        Line line = new Line(new Point3d(0, 0, 0), new Point3d(10, 10, 0)); 
        blockTableRecord.AppendEntity(line); 

        transaction.AddNewlyCreatedDBObject(line, true); 

        transaction.Commit(); 
       } 
      } 
     } 
    } 

    private void AddCircleToDrawing() 
    { 
     using (DocumentLock lockedDocument = Application.DocumentManager.MdiActiveDocument.LockDocument()) 
     { 
      using (Database database = Application.DocumentManager.MdiActiveDocument.Database) 
      { 
       using (Transaction transaction = database.TransactionManager.StartTransaction())//Start the transaction 
       { 
        //Open the block table for read 
        BlockTable blockTable = transaction.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable; 

        //Open the block table record model space for write 
        BlockTableRecord blockTableRecord = (BlockTableRecord)transaction.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite); 

        Circle circle = new Circle(new Point3d(0, 0, 0), new Vector3d(0, 0, 0), 10); 
        blockTableRecord.AppendEntity(circle); 

        transaction.AddNewlyCreatedDBObject(circle, true); 

        transaction.Commit(); 
       } 
      } 
     } 
    } 

Injection: Это подошел извлекал дублирования кода, но я думаю, что читаемость беден.

[CommandMethod("Test", CommandFlags.Session)] 
    public void Test() 
    { 
     PerformActionOnBlockTable(new CircleDrawer()); 
     PerformActionOnBlockTable(new LineDrawer()); 
    } 

    public interface IDraw 
    { 
     DBObject DrawObject(BlockTableRecord blockTableRecord); 
    } 

    public class CircleDrawer : IDraw 
    { 
     public DBObject DrawObject(BlockTableRecord blockTableRecord) 
     { 
      Circle circle = new Circle(new Point3d(0, 0, 0), new Vector3d(0, 0, 0), 10); 
      blockTableRecord.AppendEntity(circle); 

      return circle; 
     } 
    } 

    public class LineDrawer : IDraw 
    { 
     public DBObject DrawObject(BlockTableRecord blockTableRecord) 
     { 
      Line line = new Line(new Point3d(0, 0, 0), new Point3d(10, 10, 0)); 
      blockTableRecord.AppendEntity(line); 

      return line; 
     } 
    } 

    private void PerformActionOnBlockTable(IDraw drawer) 
    { 
     using (DocumentLock lockedDocument = Application.DocumentManager.MdiActiveDocument.LockDocument()) 
     { 
      using (Database database = Application.DocumentManager.MdiActiveDocument.Database) 
      { 
       using (Transaction transaction = database.TransactionManager.StartTransaction())//Start the transaction 
       { 
        //Open the block table for read 
        BlockTable blockTable = transaction.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable; 

        //Open the block table record model space for write 
        BlockTableRecord blockTableRecord = (BlockTableRecord)transaction.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite); 

        DBObject newObject = drawer.DrawObject(blockTableRecord); 

        transaction.AddNewlyCreatedDBObject(newObject, true); 

        transaction.Commit(); 
       } 
      } 
     } 
    } 

Инъекционное Func <>: Это, казалось, дать мне такой же результат, с лучшей читаемости.

[CommandMethod("Test", CommandFlags.Session)] 
    public void Test() 
    { 
     PerformActionOnBlockTable(AddLineToDrawing); 
     PerformActionOnBlockTable(AddCircleToDrawing); 
    } 

    private void PerformActionOnBlockTable(Func<BlockTableRecord, DBObject> action) 
    { 
     using (DocumentLock lockedDocument = Application.DocumentManager.MdiActiveDocument.LockDocument()) 
     { 
      using (Database database = Application.DocumentManager.MdiActiveDocument.Database) 
      { 
       using (Transaction transaction = database.TransactionManager.StartTransaction())//Start the transaction 
       { 
        //Open the block table for read 
        BlockTable blockTable = transaction.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable; 

        //Open the block table record model space for write 
        BlockTableRecord blockTableRecord = (BlockTableRecord)transaction.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite); 

        DBObject newObject = action(blockTableRecord); 

        transaction.AddNewlyCreatedDBObject(newObject, true); 

        transaction.Commit(); 
       } 
      } 
     } 
    } 

    private DBObject AddLineToDrawing(BlockTableRecord blockTableRecord) 
    { 
     Line line = new Line(new Point3d(0, 0, 0), new Point3d(10, 10, 0)); 
     blockTableRecord.AppendEntity(line); 

     return line; 
    } 

    private DBObject AddCircleToDrawing(BlockTableRecord blockTableRecord) 
    { 
     Circle circle = new Circle(new Point3d(0, 0, 0), new Vector3d(0, 0, 0), 10); 
     blockTableRecord.AppendEntity(circle); 

     return circle; 
    } 

Я могу честно сказать, что я не много сделал с DI, поэтому я совершенно новичок в этом. Может ли кто-нибудь из вас более опытных разработчиков дать мне Pro/Con двух разных подходов? Есть ли что-нибудь в последнем подходе, это красный флаг? Это кажется более читаемым, чем второй подход. Может быть, я даже не совсем понимаю инъекцию ... Спасибо заранее за вход!

ответ

5

Вы могли бы сделать простой рефакторинг вместо вариантов предоставленных вами:

[CommandMethod("Test", CommandFlags.Session)] 
public void Test() { 
    AddLineToDrawing(); 
    AddCircleToDrawing(); 
} 

private void AddLineToDrawing() { 
    CreateObjectOnBlockTable(
    new Line(new Point3d(0, 0, 0), new Point3d(10, 10, 0))); 
} 

private void AddCircleToDrawing() { 
    CreateObjectOnBlockTable(
    new Circle(new Point3d(0, 0, 0), new Vector3d(0, 0, 0), 10)); 
} 

private void CreateObjectOnBlockTable(DBObject dbObject) { 
    using (var lockedDocument = Application.DocumentManager.MdiActiveDocument.LockDocument()) 
    using (var database = Application.DocumentManager.MdiActiveDocument.Database) 
    using (var transaction = database.TransactionManager.StartTransaction()) { 
    // Open the block table for read 
    var blockTable = (BlockTable)transaction.GetObject(database.BlockTableId, OpenMode.ForRead); 

    // Open the block table record model space for write 
    var blockTableRecord = (BlockTableRecord)transaction.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite); 

    blockTableRecord.AppendEntity(dbObject); 
    transaction.AddNewlyCreatedDBObject(dbObject, true); 
    transaction.Commit(); 
    } 
} 

Я думаю, что это более читаемое.

UPDATE: Для выполнения специальной логики мне нравится идея использования делегатов. Я бы реорганизовать код так:

private void CreateObjectOnBlockTable(DBObject dbObject) { 
    PerformActionOnBlockTable((transaction, blockTableRecord) => { 
    blockTableRecord.AppendEntity(dbObject); 
    transaction.AddNewlyCreatedDBObject(dbObject, true);  
    }); 
} 

private void PerformActionOnBlockTable(Action<Transaction, BlockTableRecord> action) { 
    using (var lockedDocument = Application.DocumentManager.MdiActiveDocument.LockDocument()) 
    using (var database = Application.DocumentManager.MdiActiveDocument.Database) 
    using (var transaction = database.TransactionManager.StartTransaction()) { 
    // Open the block table for read 
    var blockTable = (BlockTable)transaction.GetObject(database.BlockTableId, OpenMode.ForRead); 

    // Open the block table record model space for write 
    var blockTableRecord = (BlockTableRecord)transaction.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite); 

    // Run specific logic 
    action(transaction, blockTableRecord); 

    transaction.Commit(); 
    } 
} 

(остальная часть кода будет таким же)

PerformActionOnBlockTable могут быть повторно использованы для выполнения произвольной логики, используя транзакцию и запись блока таблицы.

+0

Да, это тоже сработает! Полностью пропустил этот подход, +1 за его уловку :) Это затруднило бы логику добавления элемента, если это необходимо. Спасибо, что нашли время ответить! – JSprang

+0

Я уточню ответ для специальной обработки логики. –

1

Можно утверждать, что оба примера инъекций - это то же самое - отправка интерфейса или делегата в методе PerformAction... не имеет значения и действительно является вопросом вкуса. При этом отдельная реализация класса для фигур позволит классу PerformAction... быть open for extension but closed for modification. Все ваши формы будут расширениями, и ваш метод PerformAction... никогда не должен изменяться.

По иронии судьбы, формы the canonical example of the Open/Closed Principle.

+0

Эй, Остин, приятно слышать от вас и благодарить за вход! Мне очень интересно вникать в ссылку «Открытый/Закрытый Принцип», которую вы поделили. – JSprang

 Смежные вопросы

  • Нет связанных вопросов^_^