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();
                }
            }
        }
    }

注入:这种方法去除了重复代码,但我认为可读性很差。

[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();
                }
            }
        }
    }

Injecting 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 吗?最后一种方法中有什么是危险信号吗?它似乎比第二种方法更具可读性。也许我什至不完全理解注射......提前感谢您的输入!

4

2 回答 2

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(); 
  } 
} 

我认为这更具可读性。

更新:为了运行特殊的逻辑,我喜欢使用委托的想法。我会像这样重构代码:

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可以重复使用事务和块表记录来运行任意逻辑。

于 2010-09-29T19:56:20.593 回答
1

有人可能会争辩说,您的两个注入示例实际上是完全相同的事情——在PerformAction...方法中发送接口或委托是无关紧要的,实际上是一个品味问题。话虽如此,形状的单独类实现将允许PerformAction...该类对扩展开放但对修改关闭。你所有的形状都是扩展,你的PerformAction...方法永远不必改变。

具有讽刺意味的是,Shapes 是Open/Closed 原则的典型例子

于 2010-10-08T17:44:44.720 回答