我有一个向AutoCad绘图添加元素的项目。我注意到我开始在多种方法中编写相同的十行代码(为简单起见仅显示两行)。
初步实施: 你会注意到唯一真正改变的是添加一个Line而不是一个Circle。
[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();
}
}
}
}
注入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吗?最后一种方法中有什么东西是红旗吗?它似乎比第二种方法更具可读性。也许我甚至都不完全理解注射...提前感谢您的投入!
答案 0 :(得分: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
来使用事务和块表记录来运行任意逻辑。
答案 1 :(得分:1)
有人可能会争辩说,你的两个注射例子实际上是完全相同的 - 在PerformAction...
方法中发送一个接口或一个委托是无关紧要的,而且真的是一个品味问题。话虽这么说,形状的单独类实现将允许PerformAction...
类为open for extension but closed for modification。你的所有形状都是扩展,你的PerformAction...
方法永远不需要改变。
具有讽刺意味的是,形状为the canonical example of the Open/Closed Principle。