c# - 如何使用抽象工厂设计模式在 C# 中打开子窗口并绘制/绘制形状?
问题描述
我正在使用 c# 开发一个简单的命令行图形应用程序。 就像上面一样,在单击调试/运行或在下面的窗口中键入运行后,程序会逐行检查预定义的语法。
private void execute()
{
Output outputWindow = new Output(); //object of output window
compiler = new Compiler(outputWindow); //sending object of output window to compiler
//get all text and save in lines string array
string output = "";
string[] lines = GetActiveEditor().Lines;
lines = lines.Where(x => !string.IsNullOrEmpty(x)).ToArray();
if (lines == null || lines.Length == 0)
{
consoleBox.Text += "\n Error: Compiling Failed. Empty File.";
}
else
{
foreach (var line in lines)
{
output = compiler.Compile(line);
consoleBox.Text += "\n" + output;
if (output.Contains("Error"))
{
break;
}
}
}
}
private void ToolBtnDebug_Click(object sender, EventArgs e)
{
consoleBox.Clear();
consoleBox.Text = " \n CPaint Compiler:- Compiling Started... \n";
execute();
}
// In Compiler
string[] commands = { "clear", "reset", "rectangle", "circle", "triangle", "position pen", "pen draw" };
Public string Line { get; set; }
Public Output outputWindow;
public Compiler(Output form)
{
outputWindow = form;
}
//checks syntax
public bool IsSyntax(string syntax)
{
bool result = false;
if (Array.Exists(commands, element => element == syntax.ToLower().Trim()))
{
result = true;
}
return result;
}
//Compile class
public string Compile(string line)
{
string output = "";
//splitting the line by comma"," and small brackets "()" and assigning into an string a`enter code here`rray
string[] code = line.Split(',', '(', ')');
//removing extra spaces
code = code.Where(x => !string.IsNullOrEmpty(x)).ToArray();
bool checkSyntax = IsSyntax(code[0]);
if (checkSyntax == true)
{
if (code[0].Trim().ToLower().Equals("circle"))
{
try
{
int parameter1 = Int32.Parse(code[1]);
int parameter2 = Int32.Parse(code[2]);
//string shapeType = "circle";
ShapeFactory shapeFactory = new ShapeFactory();
Circle circle = shapeFactory.GetShape("circle").Shape as Circle;
circle.Draw(12, 12);
output = "command executed successfully: parameter is" + parameter1;
// output = "is numeric ";
}
}
catch (Exception ex)
{
Console.WriteLine("Exception Message: " + ex.Message);
output = "\n Parameter Error : Invalid/Insufficient Parameter. \n";
}
}
在形状工厂方法中:
class ShapeFactory:AbstractFactory
{
public override FactoryShape GetShape(string shapeType)
{
FactoryShape factoryShape = null;
if (shapeType.Equals("circle"))
{
factoryShape = new FactoryShape(new Circle());
}
return factoryShape;
}
}
//Circle Method Code:
namespace CPaint.Class
{
class Circle
{
Graphics graphics;
public void Draw(float initX, float initY)
{
Output outputWindow=new Output();
Graphics graphics=outputWindow.outputArea.CreateGraphics();
outputWindow.outputArea.Image=Color.Red;
Pen pen = new Pen(Color.Black, 4);
SolidBrush brush = new SolidBrush(Color.Black);
graphics.FillEllipse(brush, 12, 12, 12, 12);
graphics.DrawEllipse(pen, 12, 12, 12, 12);
Console.WriteLine("ok drawing circle for you" + initX + " " + initY);
output.show();
}
}
}
此代码打开两个读取的空输出窗口,而不是应该在同一个输出窗口中绘制两个圆圈。请帮忙,我三天以来一直卡在这里。提前致谢。
解决方案
首先,我们需要改进您的设计。
工厂模式只有在您编码抽象时才有意义,这意味着工厂应该创建具体类型,但您不应该知道具体类型而只知道抽象类型。在您的设计中并非如此。您说您正在使用抽象工厂模式,但是您将创建的对象转换为 Circle,这是“编码到实现”。
Compiler 将行编译为 Shapes 并执行它们。编译器应该只将文本(代码)转换为可执行对象,而不应该执行它们。不幸的是,使用您当前的设计,无法将创建的形状传递到输出表单并绘制它们。
您需要将所有已编译的 Shapes 传递到您的输出表单中,并且应该在 OnPaint 覆盖中绘制,其中运行时重新绘制控件(表单)的表面
抽象(形状):
public abstract class Shape
{
public abstract void Draw(Graphics surface);
}
具体类型:
public class Circle : Shape
{
public float Radius { get; set; }
public override void Draw(System.Drawing.Graphics surface)
{
surface.DrawEllipse(Pens.Black, 0, 0, Radius, Radius);
}
}
public class Rectangle : Shape
{
public float Width { get; set; }
public float Height { get; set; }
public override void Draw(System.Drawing.Graphics surface)
{
surface.DrawRectangle(Pens.Black, 0, 0, Width, Height);
}
}
这是我实现中的 ShapeFactory
public class ShapeFactory
{
public static Shape CreateShape(string shapeName, params string[] parameters)
{
switch (shapeName)
{
case "circle":
return new Circle() { Radius = Convert.ToSingle(parameters[0]) };
case "rectangle":
return new Rectangle { Width = Convert.ToSingle(parameters[0]), Height = Convert.ToSingle(parameters[1]) };
default:
throw new NotSupportedException("shapeName");
}
}
}
编译器:
public Shape Compile(string line)
{
string[] code = line.Split(new char[] { ',', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
if (IsSyntax(code[0]))
{
try
{
return ShapeFactory.CreateShape(code[0], code.Skip(1).ToArray());
}
catch (Exception shapeCreationException)
{
// Exception handling here.
// . . .
}
}
else
{
// Syntax Error handling here
// . . .
}
return null;
}
最后是输出形式:
public partial class Output : Form
{
public List<Shape> Shapes { get; set; }
public Output()
{
Shapes = new List<Shape>();
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
foreach (Shape shapeToDraw in Shapes)
{
shapeToDraw.Draw(e.Graphics);
}
}
}
和 execute() 方法:
private void execute()
{
Output outputWindow = new Output();
Compiler compiler = new Compiler();
string[] lines = { "circle(24)", "rectangle(80,56)" };
foreach (var line in lines)
{
try
{
Shape compiledShape = compiler.Compile(line);
outputWindow.Shapes.Add(compiledShape);
}
catch
{
// Exception handling here
// . . .
}
}
outputWindow.Show();
outputWindow.Invalidate();
}
这是经过测试和工作的。
如果您不了解某些内容或无法完成这项工作,请发表评论,但不幸的是,由于其设计缺陷,您的案例没有简单的修复。
推荐阅读
- java - 在 Java 中的另一个更大的数组中查找一个数组
- android - android应用程序中多构建类型的不同启动器应用程序图标
- apache-spark - Spark Difference between local and standalone
- javascript - 弹出的 Expo 应用程序 (ExpoKit) 在首次启动时无法在离线模式下工作
- python - 如何使用来自其他列的日期/时间信息在 Pandas 中创建新列
- wordpress - 我正在使用 wordpress 和报纸主题,并想在点击后显示我的帖子,它将在新标签中打开
- spring-boot - 抑制 Spring Boot 生成的 Vary:* 响应标头
- c# - 在 C# 中接受输入时出现 System.formatException
- javascript - 调整对象结果Javascript
- javascript - 我可以通过 dart 调用自定义 javascript 文件吗