[这种常见的养孩子模式,很容易将孩子养成一个讨债的主子]前段时间偶然看到一个新闻,一位单亲妈妈含辛茹苦打工将儿子送到国外留学,自己连饭都吃不起了,将钱寄给国外的儿子,而儿子在他乡却过着最奢侈的生活。最后这位妈妈实在没有钱给儿...+阅读
动机:
在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的改变,将会给子类带来很繁重的变更负担,甚至破坏原有设计。
如何在不更改类层次结构的前提下,在运行时根据需要透明的为类层次结构上的各个类动态添加新的操作,从而避免上述问题?
意图:
标识一个作用于某对象结构中的各元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。
public abstract class Shape
{
public abstract void Draw();
public abstract void MoveTo(Point p);
}
public class Rectangle : Shape
{
public override void Draw()
{
}
}
public class Circle : Shape
{
public override void Draw()
{
}
}
public class Line : Shape
{
public override void Draw()
{
}
}
在上述代码中,我们有一个抽象基类Shape,他定义了抽象方法Draw,Rectangle、Circle、Line继承了Shape类的方法,并且实现了Draw方法,但是当我们需要增加一个方法MoveTo时,我们必不可少的需要在各个子类中重写MoveTo方法,那么现在就带来了一个问题,当我们基类的方法不能完全确定,也就是稳定的时候,我们如何来进行解藕。
public abstract class Shape
{
public abstract void Draw();
预料到将来会引入新的操作
public abstract void Accept(ShapeVisitor visitor);
}
public abstract class ShapeVisitor
{
重载的关系,Visit方法参数不是基类型,是具体类型
public abstract void Visit(Rectangle shape);
public abstract void Visit(Circle shape);
public abstract void Visit(Line shape);
}
public class MyVisitor : ShapeVisitor
{
public override void Visit(Rectangle shape)
{
增加对Rectangle的操作
}
public override void Visit(Circle shape)
{
增加对Circle的操作
}
public override void Visit(Line shape)
{
增加对Line的操作
}
}
public class Rectangle : Shape
{
public override void Draw()
{
} public override void Accept(ShapeVisitor visitor)
{
这里是编译时确定的,不是运行时确定
如果这个调用写到Shape基类里,编译器编译的时候
不知道编译那个方法。编译会报错,因为没有
Visit(Shape shape)方法。
visitor.Visit(this);
}
}
public class Circle : Shape
{
public override void Draw()
{
}
public override void Accept(ShapeVisitor visitor)
{
visitor.Visit(this);
}
}
public class Line : Shape
{
public override void Draw()
{
}
public override void Accept(ShapeVisitor visitor)
{
visitor.Visit(this);
}
}
class App
{
ShapeVisitor visitor;
public App(ShapeVisitor visitor)
{
this.visitor = visitor;
}
public void Process(Shape shape)
{
Examda提示:两处多态:
1、Accept方法的调用对象Shape
2、Accept方法的参数Visitor
shape.Accept(visitor);
}
}
class Program
{
static void Main(string[] args)
{
App app = new App(new MyVisitor());
app.Process(new Line());
}
}
现在,我们在Shape类中定义了一个Accept方法,这个方法也是一个抽象方法,并且Rectangle、Circle、Line实现了Accept方法。并且Accept方法有一个参数ShapeVisitor。现在转到ShapeVisitor类,定义了Visit方法,并且有三个重载,每个Visit方法的参数都是Shape的派生类。在Rectangle、Circle和Line三个类中,我们实现的Accept方法都是将this指针传递给Visit方法。
现在有一个具体的MyVisitor类继承于ShapeVisitor类,并且在此类中每个Visit方法的重载,根据传递的图形不同做具体的动作。
在App类中的process方法,根据传入的图形对象和访问者对象来形成了两处多态。当我们在Shape中需要增加一种方法的时候,我们不需要改写Shape类及其派生类,我们仅仅只需要增加一种Visitor类,并将新增的Visitor类传递到App里。
要点:
Visitor模式通过所谓的双重分发(double dispatch)来实现在不更改Element类层次结构的前提下,在运行时透明的为类层次结构上的各个类动态添加新的操作。
所谓双重分发即Visitor模式中间包括了两个多态分发:第一个为Accept方法的多态辨析;第二个为Visit方法的多态辨析(重载)
Visitor模式缺点在于扩展类层次结构(添加新的Element子类),会导致Visitor类的改变,因此Visitor模式使用户Element类层子结构稳定,而其中的操作却经常面临频繁改动。
当我们需要增加一个Shape的子类时,我们需要给ShapeVisitor类添加一个Visit函数,并且ShapeVisitor的每个派生类也必须添加。
以下为关联文档:
如何招聘员工五大性格模式招聘好员工单纯注重经验的招聘方法在今天似乎已经落伍。如果你的公司每时每刻都在变化,如果你的人员需要快速地适应各种新观点,你就需要了解并运用本文以下的新观点。什么样的人才适合...
这3种家庭模式下养出的孩子,性格往往有大缺陷!相信每个家长都知道,家庭是一个人出生后最早接触的生活环境,是幼儿最早接触的生活天地,也是他们成长的最主要场所。一天中,他们与父母在一起的时间也最长,父母是孩子的第一任老...
职场12个最致命的行为模式华德普与巴特勒认为:每个人或多或少都具备下面12种行为模式的影子,在迈向成功之路时,不论主管或基层员工,都有必要时时检视自己。1、总觉得自己不够好这种人虽然聪明、有历练,...
C#基础State模式行为型模式在软件构建过程中,考试大提示:某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同,如何在运行时根据对象...
C#基础Memento备忘录模式行为型模式在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态.如果使用一些共有接口来让其他对象得到对象的状态,便会暴...
五种针对对抗的行为模式10.对抗 孩子们在探索周围和远处新东西的同时也带来了新的危险、未知的对抗以及新的社会关系,他可以从中受益匪浅。这里有五种行为模式、五种针对对抗的反应行为:攻击性反应(...