rainit2006 / C-Program

C# Program knowledge
0 stars 0 forks source link

Design Pattern #32

Open rainit2006 opened 6 years ago

rainit2006 commented 6 years ago

https://www.jianshu.com/p/61b67ca754a3 http://www.runoob.com/design-pattern/filter-pattern.html http://www.cnblogs.com/abcdwxc/archive/2007/10/30/942834.html

rainit2006 commented 6 years ago

Abstract Factory 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。 意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 主要解决:主要解决接口选择的问题。 何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。 如何解决:在一个产品族里面,定义多个产品。 关键代码:在一个工厂里聚合多个同类产品。 使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。

Abstract Factory注意的几点: 如果不存在”多系列对象创建“的需求变化,则没必要应用Abstract Factory模式,静态工厂方法足矣。 "系列对象"指的是这些对象之间有相互依赖、或作用的关系。例如一个游戏开场景: 我们需要构造"道路"、"房屋"、"地道","从林"...等等系列对象。 Abstract Factory模式主要在于应对"新系列"的需求变动。其缺点在于难以应对”新对象“的需求变动。

image

rainit2006 commented 6 years ago

工厂模式(Factory Pattern)

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。 主要解决:主要解决接口选择的问题。 何时使用:我们明确地计划不同条件下创建不同实例时。 如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

image

rainit2006 commented 6 years ago

单例模式(Singleton Pattern) 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 主要解决:一个全局使用的类频繁地创建与销毁。 何时使用:当您想控制实例数目,节省系统资源的时候。 如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。 关键代码:构造函数是私有的。

image

http://www.runoob.com/design-pattern/singleton-pattern.html

rainit2006 commented 6 years ago

建造者模式(Builder Pattern) 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。 何时使用:一些基本部件不会变,而其组合经常变化的时候。 如何解决:将变与不变分离开。 关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。 应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。 优点: 1、建造者独立,易扩展。 2、便于控制细节风险。 缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。 使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。 注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

image

image

rainit2006 commented 6 years ago

原型模式(Prototype Pattern) 意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 主要解决:在运行期建立和删除原型。 何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。 如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。 关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。 应用实例: 1、细胞分裂。 2、JAVA 中的 Object clone() 方法。

动机(Motivate): 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着 剧烈的变化,但是它们却拥有比较稳定一致的接口。 如何应对这种变化?如何向“客户程序(使用这些对象的程序)"隔离出“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变? 意图(Intent):

我们将创建一个抽象类 Shape 和扩展了 Shape 类的实体类。下一步是定义类 ShapeCache,该类把 shape 对象存储在一个 Hashtable 中,并在请求的时候返回它们的克隆。 PrototypPatternDemo,我们的演示类使用 ShapeCache 类来获取 Shape 对象。 image

Prototype模式对于“如何创建易变类的实体对象“采用“原型克隆”的方法来做,它使得我们可以 非常灵活地动态创建“拥有某些稳定接口中”的新对象----所需工作仅仅是注册的地方不断地Clone. Prototype模式中的Clone方法可以利用.net中的object类的memberwiseClone()方法或者序列化来实现深拷贝。 有关创建型模式的讨论: Singleton模式解决的是实体对象个数的问题。除了Singleton之外,其他创建型模式解决的是都是new 所带来的耦合关系。 Factory Method ,Abstract Factory,Builder都需要一个额外的工厂类来负责实例化“易变对象”,而Prototype则是通过原型(一个特殊的工厂类)来克隆“易变对象”。 如果遇到“易变类”,起初的设计通常从Factory Mehtod开始,当遇到更多的复杂变化时,再考虑重重构为其他三种工厂模式(Abstract Factory,Builder,Prototype). 分类: 设计模式

rainit2006 commented 6 years ago

适配器模式(Adapter Pattern) 意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 主要解决:主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。 何时使用: 1、系统需要使用现有的类,而此类的接口不符合系统的需要。 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。 3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。) 如何解决:继承或依赖(推荐)。 关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。 应用实例: 1、美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。 2、JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。 3、在 LINUX 上运行 WINDOWS 程序。 4、JAVA 中的 jdbc。 image image

我们有一个 MediaPlayer 接口和一个实现了 MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。 我们还有另一个接口 AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。 我们想要让 AudioPlayer 播放其他格式的音频文件。为了实现这个功能,我们需要创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。 AudioPlayer 使用适配器类 MediaAdapter 传递所需的音频类型,不需要知道能播放所需格式音频的实际类。AdapterPatternDemo,我们的演示类使用 AudioPlayer 类来播放各种格式。

image

rainit2006 commented 6 years ago

桥接(Bridge)模式 意图:将抽象部分与实现部分分离,使它们都可以独立的变化。 主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。 何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。 如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。 关键代码:抽象类依赖实现类。 应用实例: 1、猪八戒从天蓬元帅转世投胎到猪,转世投胎的机制将尘世划分为两个等级,即:灵魂和肉体,前者相当于抽象化,后者相当于实现化。生灵通过功能的委派,调用肉体对象的功能,使得生灵可以动态地选择。 2、墙上的开关,可以看到的开关是抽象的,不用管里面具体怎么实现的。

应用场景: image image 实际上,蜡笔和毛笔的关键一个区别就在于笔和颜色是否能够分离。【GOF95】桥梁模式的用意是"将抽象化 (Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。关键就在于能否脱耦。蜡笔的颜色和蜡笔本身是分不 开的,所以就造成必须使用36支色彩、大小各异的蜡笔来绘制图画。而毛笔与颜料能够很好的脱耦,各自独立变化,便简化了操作。

++++++++++++++

我们有一个作为桥接实现的 DrawAPI 接口和实现了 DrawAPI 接口的实体类 RedCircle、GreenCircle。Shape 是一个抽象类,将使用 DrawAPI 的对象。BridgePatternDemo,我们的演示类使用 Shape 类来画出不同颜色的圆。 image

使用 Shape 和 DrawAPI 类画出不同颜色的圆。

public class BridgePatternDemo {
   public static void main(String[] args) {
      Shape redCircle = new Circle(100,100, 10, new RedCircle());
      Shape greenCircle = new Circle(100,100, 10, new GreenCircle());

      redCircle.draw();
      greenCircle.draw();
   }
}
rainit2006 commented 6 years ago

装饰器模式(Decorator Pattern) 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。 何时使用:在不想增加很多子类的情况下扩展类。 如何解决:将具体功能职责划分,同时继承装饰者模式。 关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。

我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。 RedShapeDecorator 是实现了 ShapeDecorator 的实体类。 DecoratorPatternDemo,我们的演示类使用 RedShapeDecorator 来装饰 Shape 对象。 image

看代码更好理解:http://www.runoob.com/design-pattern/decorator-pattern.html

创建实现了 Shape 接口的抽象装饰类。
public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;

   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }

   public void draw(){
      decoratedShape.draw();
   }    
}

创建扩展了 ShapeDecorator 类的实体装饰类。
public class RedShapeDecorator extends ShapeDecorator {

   public RedShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);        
   }

   @Override
   public void draw() {
      decoratedShape.draw();           
      setRedBorder(decoratedShape);
   }

   private void setRedBorder(Shape decoratedShape){
      System.out.println("Border Color: Red");
   }
}

使用 RedShapeDecorator 来装饰 Shape 对象。

public class DecoratorPatternDemo {
   public static void main(String[] args) {

      Shape circle = new Circle();

      Shape redCircle = new RedShapeDecorator(new Circle());

      Shape redRectangle = new RedShapeDecorator(new Rectangle());
      System.out.println("Circle with normal border");
      circle.draw();

      System.out.println("\nCircle of red border");
      redCircle.draw();

      System.out.println("\nRectangle of red border");
      redRectangle.draw();
   }
}

Decorator在.NET(Stream)中的应用: image

rainit2006 commented 6 years ago

观察者模式(Observer Pattern) 比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。 意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。 何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。 如何解决:使用面向对象技术,可以将这种依赖关系弱化。 关键代码:在抽象类里有一个 ArrayList 存放观察者们。

image

rainit2006 commented 6 years ago

命令模式(Command Pattern) 请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。 如何解决:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。 关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口

我们首先创建作为命令的接口 Order,然后创建作为请求的 Stock 类。实体命令类 BuyStock 和 SellStock,实现了 Order 接口,将执行实际的命令处理。创建作为调用对象的类 Broker,它接受订单并能下订单。 Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令。CommandPatternDemo,我们的演示类使用 Broker 类来演示命令模式。 image

public class CommandPatternDemo {
   public static void main(String[] args) {
      Stock abcStock = new Stock();

      BuyStock buyStockOrder = new BuyStock(abcStock);
      SellStock sellStockOrder = new SellStock(abcStock);

      Broker broker = new Broker();
      broker.takeOrder(buyStockOrder);
      broker.takeOrder(sellStockOrder);

      broker.placeOrders();
   }
}
rainit2006 commented 6 years ago

外观模式(Facade Pattern) 隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。

主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。 何时使用: 1、客户端不需要知道系统内部的复杂联系,整个系统只需提供一个"接待员"即可。 2、定义系统的入口。 如何解决:客户端不与系统耦合,外观类与系统耦合。 关键代码:在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。

我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。下一步是定义一个外观类 ShapeMaker。 ShapeMaker 类使用实体类来代表用户对这些类的调用。FacadePatternDemo,我们的演示类使用 ShapeMaker 类来显示结果。 image

创建一个外观类。
ShapeMaker.java
public class ShapeMaker {
   private Shape circle;
   private Shape rectangle;
   private Shape square;

   public ShapeMaker() {
      circle = new Circle();
      rectangle = new Rectangle();
      square = new Square();
   }

   public void drawCircle(){
      circle.draw();
   }
   public void drawRectangle(){
      rectangle.draw();
   }
   public void drawSquare(){
      square.draw();
   }
}

使用该外观类画出各种类型的形状。
public class FacadePatternDemo {
   public static void main(String[] args) {
      ShapeMaker shapeMaker = new ShapeMaker();

      shapeMaker.drawCircle();
      shapeMaker.drawRectangle();
      shapeMaker.drawSquare();        
   }
}
rainit2006 commented 6 years ago

策略模式(Strategy Pattern) 一个类的行为或其算法可以在运行时更改

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。 主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。 何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。 如何解决:将这些算法封装成一个一个的类,任意地替换。 关键代码:实现同一个接口。

我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。 StrategyPatternDemo,我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化。 image

public class StrategyPatternDemo {
   public static void main(String[] args) {
      Context context = new Context(new OperationAdd());        
      System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

      context = new Context(new OperationSubstract());        
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

      context = new Context(new OperationMultiply());        
      System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
   }
}
rainit2006 commented 6 years ago

状态模式(State Pattern) 类的行为是基于它的状态改变的 意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。 主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。 何时使用:代码中包含大量与对象状态有关的条件语句。 如何解决:将各种具体的状态类抽象出来。 关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if...else 等条件选择语句。

image

public class StatePatternDemo {
   public static void main(String[] args) {
      Context context = new Context();

      StartState startState = new StartState();
      startState.doAction(context);

      System.out.println(context.getState().toString());

      StopState stopState = new StopState();
      stopState.doAction(context);

      System.out.println(context.getState().toString());
   }
}