设计模式

  • VISITOR模式
动机:假设我们有一个接口,然后有一些实现类,这个接口已经发布出去了,不能改了。但我们希望这个接口能够方便的添加一些新的函数接口,显然不能改接口,怎么办。这个时候VISITOR模式就起作用了。
模式描述:VISITOR模式可以让我们在不改变原有接口的前提下,向接口添加新功能,这样仿佛就达到了想接口中添加新方法的效果。从实现来说,一个VISITOR类定义了对于所有原有interface子类的某一个共同的操作。
模式实现:
abstract class BaseClass
{
     public int memberProperty1;
     public int memberProperty2;
     public void acceptVisitor(Visitor visitor);
}

class ChildClass1 extends BaseClass
{
     public void acceptVisitor(Visitor visitor)
     {
         visitor.visitChildClass1(this); 
     }
}

class ChildClass2 extends BaseClass
{
     public void acceptVisitor(Visitor visitor)
     {
          visitor.visitChildClass2(this);
     }
}

abstract class Visitor
{
     public void visitChildClass1(ChildClass1 object);
     public void visitChildClass2(ChildClass2 object);
}

class WriteProperty1Visitor
{
     public void visitChildClass1(ChildClass1 object){...}
     public void visitChildClass2(ChildClass2 object){...}
}

class WriteProperty2Visitor
{
     public void visitChildClass1(ChildClass1 object){...}
     public void visitChildClass2(ChildClass2 object){...}
}

以上的例子中,通过添加两个visitor子类,就实现了想原接口中添加两个函数的效果。
使用VISITOR模式有个限制,那就是接口的子类要固定下来,不可以变,变了访问者模式就不行了。


  • DECORATOR模式
动机:通常我们要改变某一个类的某一个功能,都是继承这个类,并重写一些函数。这样做有个副作用,就是随着要定制的功能越来越多,子类就会越来越多,也就是常说的子类爆炸。但仔细分析,某一些情况下,一些定制可以通过已有的子类进行组合达到,这样就可以有效减少子类的数目。DECORATOR就是处理这种情况。
例子:假设我们有一个Visual类,其中包含一个Draw方法。我们希望如下三种定制:画的时候添加一个实线边框;添加一个虚线边框;同时添加实线和虚线边框。按照传统的方法需要实现三个子类,按照decorator的方法,只需要添加两个子类。实现如下:
class Visual
{
     public void draw();
}

class ConcreateBorderDecorator extends Visual
{
     private Visual innerVisual;
     public ConcreateBorderDecorator(Visual innerVisual) {this.innerVisual = innerVisual;}

     public override void draw()
     {
          drawConcreateBorder();
          innerVisual.draw(); 
     }
}

class DashBorderDecorator extends Visual
{
     private Visual innnerVisual;
     public DashBorderDecorator(Visual innerVisual) {this.innerVisual = innerVisual;}
     
     public override void draw()
     {
          drawDashBorder();
          innerVisual.draw();
     }
     
}

// 假设已有一个XInnerVisual
// 画innervisual自己
XInnerVisual.draw()
// 画实现边框再画InnerVisual
ConcreateBorderDecorator decorator = new ConcreateBorderDecorator(XInnerVIsual);
decorator.draw();
// 画虚线边框再画InnerVisual
DashBorderDecorator decorator = new DashBorderDecorator(XInnerVisual);
decorator.draw();
// 画实线再画虚线再画Visual
ConcreateBorderDecorator decorator = new ConcreateBorderDecorator(new DashBorderDecorator(XInnerVisual));
decorator.draw();

从以上的实现看出,Decorator模式实际是一个Has-a的方式的应用,一个decorator包含了被修饰的object,这样就可以在调用被修饰object方法之前或之后做一些事情。


  • Visitor和Decorator的比较:Visitor是在不修改被访问接口定义的前提下,为被访问接口提供更多的方法。Decorator是为了修改原方法的实现(并没有增加方法的种类),但不想定义过多的子类

  • COMPOSITE模式
描述:提供了一种【递归】的组合方式,在NextGen的源码中,Element.Components就是这样的一种方式。他的关键是元素与容器都是同种类型
典型实现:
class Element
{
     public IEnumerable<Element> Components;
}

有了这样的定义,我们就可以【递归】地做很多事请:
class Element
{
     public IEnumerable<Element> Components;

     public void doSomething()
     {
          this.do();
          foreach(var compoenent in Compoents)
          {
              component.doSomething(); 
          } 
     }

     private void do() {...}
}

  •  FLYWEIGHT模式
描述:在做文本编辑程序的时候,我们需要给每一个字符都定义他的字号,颜色等。对于一片有10000个字符的文章,我们就要定义10000个类记录字符,以及他的字号和颜色。这样就会造成使用过多的内存。但是仔细考虑,字符只有ASCII码的字符集,只是有限的数量,而且不管在什么地方,‘a’字符始终是一样的,所以字符就是一个可以共享的信息。 享元模式是定义一个类,封装一些可以共享的信息,然后将其他外部无法共享信息都通过函数参数的方式获取。在文本处理的例子中,我们可以有如下实现:
class CharactorFlyweight
{
     public char Character;
     
     public CharactorFlyweight(char c) {Character = c;}

     public void renderCharacter(int charSize, Font font, Color color) {...}
}

class CharacterFlyweightFactory
{
     private IDictionary<char, CharctorFlyweight> map;
     public CharactorFlyweight getOrCreateFlyweight(char c)
     {
          if(map.contains(c))
          {
               return map[c];
          }
          CharactorFlyweight flyweight = new CharactorFlyweight(c);
          map.add(c, flyweight);
          return flyweight;
     }
}


// 使用的代码
CharactorFlyweight flyweight = CharactorFlyweightFactory.instance().getOrCreateFlyweight('a');
flyweight.renderCharactor(1, font, red);

通过这种方式,我们可以节省很多重复的分配给保存字符的内存空间。

  • COMMAND模式
描述:这种模式是将一个指令变成一个对象,这样不仅可以执行指令,还可以对指令本身进行操作。NextGen中,Transaction就是典型代表,transaction有一个Commit()方法,这就是执行指令的方法,去完成指定的事物。但同时,也可以操作transaction本身,比如将其加入一个队列中,延迟执行。

  • STRATEGY模式
描述:这种模式是将算法变成一个对象,在Match算法中,我们就用了这种模式,每一个match step都是一个算法,我们将其封装成一个对象,然后这个对象可以被组合,从而构成了更强大的match 算法,而且针对不同的文件类型,我们也可以选择不同的MatchStep对象。

  • 行为模式的讨论:Command Strategy都是行为模式,封装变化是很多行为模式的主题, Strategy用对象封装算法,Command用对象封装指令,Mediator用对象封装通信

  • AbstractFactory, Builder, FactoryMethod
这三者有些像,最简单的是Factory Method,他的作用是将创建工作交给一个函数。
AbstractFactory和Builder有点像,都是一个类中定义一系列构造方法,只是在具体的使用上有些不一样, builder更突出“Part”的概念, 一步一步构造的概念。
abstract class Factory
{
     public Door createDoor();
     public Room createRoom();
     
}

abstract class Builder
{
     public Door buildDoor();
     public Room buildRoom();
     public Maze getMaze();// maze is composed of Door and room
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值