这是接受采访时提出的问题。
Label
有一个属性Text
在一个页面中,标签很简单Label
,在其他页面中,它可以处理以下行为中的任何一个或组合 可点击
可调整大小
可拖动如何设计应用OOP设计的标签组件原理&设计模式?
我说我会创建以下内容:
public class Label
{
public string Text{get;set;}
}
public interface IClickable
{
void Click();
}
public interface IDraggable
{
void Drag();
}
public interface IResizable
{
void Resize();
}
因此,如果客户需要Resizable Label
public class ResizableLabel:Label,IResizable
{
....
}
同样方式ClickableLable
,DraggableLabel
但是,我觉得这是不正确的方法,因为我不想添加那些具体的类。我希望避免使用ClickableAndDraggableLabel
或ClickableDraggableResizableLabel
。
是否有任何设计模式可以在不添加这些具体类的情况下解决此问题?
答案 0 :(得分:9)
我会使用Decorator pattern。它在.net世界中广泛用于不同类型的流,例如,它允许您为字节流组合加密的,压缩的文本流包装器。类图取自维基
您的情况示例在实现中并不是那么简单,但是使用不需要其他类来进行新的编译行为:
// Define other methods and classes here
public class Label
{
public string Text{get;set;}
public virtual void MouseOver(object sender, EventArgs args) { /*some logic*/ }
public virtual void Click(object sender, EventArgs args) { /*some logic*/ }
//other low level events
}
public class ClikableLabel : Label
{
private Label _label;
public ClikableLabel(Label label)
{
_label = label;
}
public override void Click(object sender, EventArgs args)
{
//specific logic
_label.Click(sender, args);
}
}
public class DraggableLabel : Label
{
private Label _label;
public DraggableLabel(Label label)
{
_label = label;
}
public override void Click(object sender, EventArgs args)
{
//specific logic
_label.Click(sender, args);
}
}
public class ResizableLabel : Label
{
private Label _label;
public ResizableLabel(Label label)
{
_label = label;
}
public override void MouseOver(object sender, EventArgs args)
{
//specific logic
_label.MouseOver(sender, args);
}
public override void Click(object sender, EventArgs args)
{
//specific logic
_label.Click(sender, args);
}
}
现在你可以
var clickableDragableLabel = new ClikableLabel(new DraggableLabel(new Label{Text = "write me!"}));
var makeItResizable = new ResizableLabel(clickableDragableLabel);
答案 1 :(得分:1)
我只有CanClick
,drag
和resize
的布尔属性,默认为true,并根据需要(或继承)进行调整。
构造函数如下
public Label(bool canClick = true, bool canDrag = true, bool canResize = true){}
如果他们一次扩展课程,可能会在以后进一步扩展
答案 2 :(得分:1)
我不认为Interface可以解决您的问题 我会做更像这样的事情:
首先,定义一个列出所有动作的枚举:
public Enum LabelAction{ None = 0, Clickable = 1, Resizable = 2, Draggable = 4 }
如果定义了多个枚举,您可以查看以下链接:
然后在类Label中定义一个成员,执行操作:
public class Label
{
private readonly LabelAction _action;
private string Text { get; set; }
public class Label(string text)
: Label(text, LabelAction.None) { }
public class Label(string text, LabelAction action)
{
this.Text = text;
this._action = action;
}
public bool CanClick
{
get
{
return this._action & LabelAction.Clickable == LabelAction.Clickable;
}
}
public bool CanResize { get { return this._action & LabelAction.Resizable == LabelAction.Resizable ;} }
public bool CanDrag { get { return this._action & LabelAction.Draggable == LabelAction.Draggable ;} }
public Click()
{
if(this.CanClick) { /* click */ }
else { throw new Exception("Not clickable");}
}
public Drag()
{
if(this.CanDrag) { /* drag */ }
else { throw new Exception("Not draggable");}
}
public Resize()
{
if(this.CanResize) { /* resize */}
else { throw new Exception("Not resizable");}
}
}
用法:
var simpleLabel = new Label("simple");
var clickable = new Label("clickable", LabelAction.Clickable);
var clickableDraggable = new Label("clickable and draggable", LabelAction.Clickable | LabelAction.Draggable);
public void DoEvent(Label label)
{
if(label.CanClick) label.Click();
if(label.CanDrag) label.Drag();
if(label.CanResize) label.Resize();
}
如果您需要添加操作,则必须向枚举LabelAction
添加一个项目,向CanDo()
类添加一个方法Do()
和一个方法Label
。不是那么多。
答案 3 :(得分:0)
您可以拥有一个实现所有接口的基类,并将其行为委托给具体的策略类。 然后你会有一个NullDraggable,nulResizeable,NullClickable默认情况下什么都不做(所以你的基本标签不可点击,可调整大小和可绘制) 然后,您创建不同的策略,如Clickable,DoubleClickable,WidthResizeable等... 然后,您将所需的组合传递给您的班级。 通过这种方式,您可以获得很多很少的策略,这些策略很容易在具有相同接口的其他组件中重用。 通过使用复合模式可以有多种行为(例如,您可以使用可点击和双击的togheter)
虽然
可能会有点过时答案 4 :(得分:0)
我认为你过分思考了面试官的想法。如果案例简单实用,为了避免过度抽象的复杂性,那么这就足够了:
public class Label
{
public string Text{get;set;}
}
public class ComlexLabel : Label
{
Click();
Drag();
Resize();
}
你可以对它进行任何操作。现在,如果对于一个挑战,你只需要一个具体的实例,并且需要单独类型的对象才能只做这些东西的组合,它再次简单 - 只是这次你必须创建类似的原型/接口:
public class Label
{
public string Text{get;set;}
}
public interface Clickable
{
Click();
}
public interface Resizable
{
Resize();
}
public interface Dragable
{
Drag();
}
public interface ClickableDragable : Clickable, Draggable
{
}
public interface ClickableResizable : Clickable, Resizable
{
}
public interface ResizableDragable : Resizable, Draggable
{
}
public interface ClickableDragableResizeable : Resizable, Clickable, Draggable
{
}
public class ComlexLabel : Lable, ClickableDragableResizeable
{
Click();
Drag();
Resize();
}
现在,您可以通过创建提供所需功能的类型来拥有ComlexLabel
的实例。像:
ResizableDragable rd = new ComlexLabel();
ClickableResizable cr = new ComlexLabel();
ClickableDragableResizeable cdr = new ComlexLabel();
现在rd
,cr
和cdr
具有不同的功能。它们背后只有一个具体的例子。通过执行
var cdr = new ComplexLabel();
你应该将ComplexLabel
构造函数设为私有,并将任务分配给某个工厂。像
var rd = Factory.GetResizableDragableLabel();
现在rd
必须只是ResizableDragable
且没有Click
功能..
答案 5 :(得分:-1)
我认为在这种情况下,没有必要重新发明轮子。即使问题明确要求OOP,也没有明确要求您忽略组件模型编程或基于事件的行为。 这就是为什么我会遵循一种允许责任分工的方法,其中Label负责在点击或拖动时通知,而SomeOtherComponent可能会或可能不会听取此类通知(事件)以执行其他逻辑。
请查看以下链接,了解这些用户操作的事件调度方法示例:
此致