- 依赖、关联、聚合、组合的区别。
- 设计模式有哪些?如何分类?
- 设计模式遵守哪些规则?
- 简单工厂模式
- 策略模式
- 装饰模式
- 代理模式
- 工厂方法模式
- 原型模式
- 模板方法
- 观察者模式
- 抽象工厂
- 状态模式
- 适配器模式
- 组合模式
- 迭代器模式
- 单例模式
- 桥接模式
- 命令模式
- 职责链模式
- 中介者模式
- 享元模式
- 解释器模式
- 访问者模式
依赖、关联、聚合、组合的区别。
依赖
:Uses a。这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A;比如类B作为参数被类A在某个method方法中使用;
关联
:Has a。这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的、关联可以是单向、双向的;表现在代码层面,为被关联类B以类属性的形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量;
聚合
:Own a。聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;比如计算机与CPU、公司与员工的关系等;表现在代码层面,和关联关系是一致的,只能从语义级别来区分;
组合
:is a part of。这种关系比聚合更强,也称为强聚合;他同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束。
设计模式有哪些?如何分类?
1.创建型模式: 1)抽象工厂; 2)生成器; 3)工厂方法; 4)原型; 5)单例; 2.结构型模式: 6)适配器; 7)桥接; 8)组合; 9)装饰; 10)外观; 11)享元; 12)代理; 3.行为模式: 13)职责链; 14)命令; 15)解释器; 16)迭代器; 17)中介者; 18)备忘录; 19)观察者 20)状态; 21)策略; 22)模板方法; 23)访问者;
设计模式遵守哪些规则?
单一职责原则
:就一个类而言,应该仅有一个引起它变化的原因。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。比如设计游戏显示区域,将绝对坐标改成相对坐标,实现程序逻辑和界面的分离。
开放-封闭原则
:开放-封闭原则:软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。
面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。
最初编写代码时,假设变化不会发生,当变化发生时,就创建抽象来隔离以后发生的同类变化。
开发人员应该仅对程序中呈现出频繁变化的那部分作出抽象,然而对于程序中的每个部分都刻意地进行抽象同样不是一个好主意。
依赖倒换原则
:依赖倒换原则:要针对接口编程,不要对实现编程
1)高层模块不应该依赖于低层模块。
2)抽象不应该依赖细节。细节应该依赖抽象。
里氏代换原则
:一个软件实体,如果使用的是一个父类的话,那么一定适用于其子类,而且它觉察不出父类对象和子类对象的区别。
正是由于子类型的可替换性才使得使用父类类型的模块在无需修改的情况下就可以扩展。
迪米特法则
:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。在类的结构设计上,每一个类都应当尽量降低成员的访问权限。其根本思想是强调了类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。
简单工厂模式
例:简单工厂模式实现计算器
(1)Operation运算类
java
public class Operation
{
private double _numberA = 0;
private double _numberB = 0;
public double NumberA{…}
public double NumberB{…}
public virtual double GetResult()
{
double result = 0;
return result;
}
}
(2)加减乘除类
java
class OperationAdd:Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA + NumberB;
return result;
}
}
class OperationSub:Operation{…}
class OperationMul:Operation{…}
class OperationDiv:Operation{…}
(3)简单运算工厂类
```java
public class OperationFactory
{
// 工厂类根据传入的类型创建特定类的不同子类
public static Operation createOperate(string operate)
{
Operation oper = null;
switch(operate)
{
case”+”:
oper = new OperationAdd();
break;
case”-”:
… …
}
return oper;
}
}
```
(4)客户端代码
```java
Operation oper;
oper = OperationFactory.createOperate(“+”);
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
```
策略模式
策略模式(Strategy)定义了算法家族,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。
(1)Strategy类定义了所有支持的算法的公共接口:
java
abstract class Strategy
{
//算法方法
public abstract void AlgorithmInterface();
}
(2)ConcreteStrategy类封装了具体的算法或行为,继承于Strategy
java
//具体算法A
class ConcreteStrategyA : Strategy
{
//算法A实现方法
public override void AlgorithmInterface()
{
Console.WriteLine("算法A实现");
}
}
//具体算法B
class ConcreteStrategyB : Strategy{…}
//具体算法C
class ConcreteStrategyC : Strategy{…}
// 上下文类维护一个策略类的引用,可以使用不同的策略类进行初始化,上下文类对用户提供一致的接口,并将实际工作委托给策略类完成
(3)Context用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用:
java
//上下文
class Context
{
Strategy strategy;
public Context(Strategy strategy)
{
this.strategy = strategy;
}
//上下文接口
public void ContextInterface()
{
strategy.AlgorithmInterface();
}
}
(4)客户端代码:
java
Context context;
context = new Context(new ConcreteStrategyA());
context.ContextInterface();
context = new Context(new ConcreteStrategyB());
context.ContextInterface();
… …
装饰模式
装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
(1)Component定义一个对象接口,可以给这些对象动态地添加职责。
java
abstract class Component
{
public abstract void Operation();
}
(2)ConcreteComponent定义一个具体的对象,也可以给这个对象添加一些职责
java
class ConcreteComponent : Component
{
public override void Operation()
{
Console.WriteLine("具体对象的操作");
}
}
// 装饰器类一定也要继承被装饰类(的抽象基类),这是实现链式操作的关键
(3)Decorator为装饰抽象类,继承了Component类,从外类来扩展Component类的功能,但对于Component来说,是无须知道Decorator存在的。
java
abstract class Decorator : Component
{
protected Component component;
public void SetComponent(Component component)
{
this.component = component;
}
public override void Operation()
{
if (component != null)
{
component.Operation();
}
}
}
(4)ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
```java
class ConcreteDecoratorA : Decorator
{
private string addedState;
public override void Operation()
{
base.Operation();
addedState = “New State”;
Console.WriteLine(“具体装饰对象A的操作”);
}
}
class ConcreteDecoratorB : Decorator
{
public override void Operation()
{
base.Operation();
AddedBehavior();
Console.WriteLine("具体装饰对象B的操作");
}
private void AddedBehavior()
{
}
}
``` (5)客户端代码:
```
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA d1 = new ConcreteDecoratorA();
ConcreteDecoratorB d2 = new ConcreteDecoratorB();
d1.SetComponent(c);
d2.SetComponent(d1);
d2.Operation();
```
代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
(1)Subject类定义了RealSubject和Proxy的公用接口,这样在任何RealSubject的地方都可以使用Proxy。
java
abstract class Subject
{
public abstract void Request();
}
(2)RealSubject类:
java
class RealSubject : Subject
{
public override void Request()
{
Console.WriteLine("真实的请求");
}
}
// 代理类和被代理类都继承于同样的基类(因此具有同样的对外接口),代理类中维护一个被代理类的引用,并将实际工作委托给被代理类完成(代理类可以添加额外的操作)。
(3)Proxy类:保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。
java
class Proxy : Subject
{
RealSubject realSubject;
public override void Request()
{
if (realSubject == null)
{
realSubject = new RealSubject();
}
realSubject.Request();
}
}
(4)客户端代码:
Proxy proxy = new Proxy();
proxy.Request();
代理模式的应用场合:
1)远程代理,为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。如WebService。
2)虚拟代理,根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。如浏览器中未打开的图片框就是通过虚拟代理来替代了真实的图片,此时代理存储了真实图片的路径和尺寸,图片仍在下载中。
3)安全代理,用来控制真实对象访问时的权限。
4)智能指引,是指当调用真实的对象时,代理处理另外一些事。如计算真实对象的引用次数,或在第一次引用一个持久对象时将它装入内存。
工厂方法模式
工厂方法模式:定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 简单工厂VS工厂方法:简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但当增加新功能时,简单工厂模式违背了“开放-封闭原则”。把工厂类抽象出一个接口,这个接口只有一个方法就是创建抽象产品的工厂方法。然后,所有的要产生具体类的工厂就去实现这个接口,这样一个简单工厂模式的工厂类就变成了一个工厂抽象接口和多个具体生成对象的工厂。当要增加新功能时就不需要更改原有的工厂类了,只要增加此功能的运算类和相应的工厂类就可以。这样整个工厂和产品体系都没有修改的变化,而只是扩展的变化。当然,工厂方法模式并不能避免修改客户端代码。
原型模式
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。其实就是从一个对象再创建另外一个可定制的对象。 (1)原型类 ```java abstract class Prototype { private string id;
// Constructor
public Prototype(string id)
{
this.id = id;
}
// Property
public string Id
{
get { return id; }
}
// 原型类需要定义一个Clone方法
public abstract Prototype Clone();
}
``` (2)具体原型类 ```java class ConcretePrototype1 : Prototype
{
// Constructor
public ConcretePrototype1(string id)
: base(id)
{
}
public override Prototype Clone()
{
// Shallow copy
return (Prototype)this.MemberwiseClone();
// MemberwiseClone方法创建当前对象的浅表副本
}
}
class ConcretePrototype2 : Prototype
{
… …
}
``` (3)客户端代码 ```java
ConcretePrototype1 p1 = new ConcretePrototype1("I");
ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
Console.WriteLine("Cloned: {0}", c1.Id);
ConcretePrototype2 p2 = new ConcretePrototype2("II");
ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
Console.WriteLine("Cloned: {0}", c2.Id);
```
模板方法
模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 (1)AbstractClass是抽象类定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法:
abstract class AbstractClass
{
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
public void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
Console.WriteLine("");
}
}
```
(2)ConcreteClass实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法的不同实现,从而使得顶级逻辑的实现各不相同。
```java
class ConcreteClassA : AbstractClass
{
public override void PrimitiveOperation1()
{
Console.WriteLine("具体类A方法1实现");
}
public override void PrimitiveOperation2()
{
Console.WriteLine("具体类A方法2实现");
}
}
class ConcreteClassB : AbstractClass
{
… …
}
```
(3)客户端代码:
```java
AbstractClass c;
c = new ConcreteClassA();
c.TemplateMethod();
c = new ConcreteClassB();
c.TemplateMethod();
```
模板方法模式特点:模板方法模式是通过把不变行为搬到超类中,去除子类中的重复代码来体现它的优势。当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。
## 外观模式
外观模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
(1)四个子系统的类:
```java
class SubSystemOne
{
public void MethodOne()
{
Console.WriteLine(" 子系统方法一");
}
}
class SubSystemTwo{…}
class SubSystemThree{…}
class SubSystemFour{…}
```
(2)外观类:
```java
class Facade
{
SubSystemOne one;
SubSystemTwo two;
SubSystemThree three;
SubSystemFour four;
public Facade()
{
one = new SubSystemOne();
two = new SubSystemTwo();
three = new SubSystemThree();
four = new SubSystemFour();
}
public void MethodA()
{
Console.WriteLine("\n方法组A() ---- ");
one.MethodOne();
two.MethodTwo();
four.MethodFour();
}
public void MethodB()
{
Console.WriteLine("\n方法组B() ---- ");
two.MethodTwo();
three.MethodThree();
}
}
```
(3)客户端调用
```java
Facade facade = new Facade();
facade.MethodA();
facade.MethodB();
```
“三层架构”使用的就是该模式。
## 建造者模式
建造者模式:也称生成器模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。用户只需指定需要建造的类型就可以得到它们,而具体的过程和细节就不需知道了。
(1)产品类,由多个部件组成
```java
class Product
{
IList<string> parts = new List<string>();
public void Add(string part)// 添加产品部件
{
parts.Add(part);
}
public void Show()
{
Console.WriteLine("\n产品 创建 ----");
foreach (string part in parts)
{
Console.WriteLine(part);
}
}
}
```
(2)抽象建造者类,确定产品由两个部件PartA和PartB组成,并声明一个得到产品建造后结果的方法GetResult。
```java
abstract class Builder
{
public abstract void BuildPartA();
public abstract void BuildPartB();
public abstract Product GetResult();
}
(3)具体建造者类
class ConcreteBuilder1 : Builder
{
private Product product = new Product();
public override void BuildPartA()
{
product.Add("部件A");
}
public override void BuildPartB()
{
product.Add("部件B");
}
public override Product GetResult()
{
return product;
}
}
class ConcreteBuilder2 : Builder
{
private Product product = new Product();
public override void BuildPartA()
{
product.Add("部件X");
}
public override void BuildPartB()
{
product.Add("部件Y");
}
public override Product GetResult()
{
return product;
}
}
(4)指挥者类,用来指挥建造过程(即调用建造者类的实际建造方法,完成建造过程以便后续返回建造好的对象)
java
class Director
{
public void Construct(Builder builder)
{
builder.BuildPartA();
builder.BuildPartB();
}
}
(5)客户端代码,客户不需要知道具体的建造过程
Director director = new Director();
Builder b1 = new ConcreteBuilder1();
Builder b2 = new ConcreteBuilder2();
director.Construct(b1);
Product p1 = b1.GetResult();
p1.Show();
director.Construct(b2);
Product p2 = b2.GetResult();
p2.Show();
观察者模式
观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 当一个对象的改变需要同时改变其他的对象,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。 观察者模式结构图:
(1)Subject类,即主题或抽象通知者。一般用一个抽象类或者一个接口实现。
```java
abstract class Subject
{
private IList
//增加观察者
public void Attach(Observer observer)
{
observers.Add(observer);
}
//移除观察者
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
// Subject类有一个Observers的列表,并有一个通知方法用来遍历调用所有Observers的方法
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
}
``` (2)Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现,更新接口通常包含一个更新方法。
```java
abstract class Observer
{
public abstract void Update();
}
``` (3)ConcreteSubject类,即具体主题。 ```java
class ConcreteSubject : Subject
{
private string subjectState;
//具体通知者状态
public string SubjectState
{
get { return subjectState; }
set { subjectState = value; }
}
}
``` (4)ConcreteObserver类,具体观察者。可以保存一个指向具体主题对象的引用。 ```java
class ConcreteObserver : Observer
{
private string name;
private string observerState;
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
//更新
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("观察者{0}的新状态是{1}",name, observerState);
}
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
}
``` (5)客户端代码 ```java
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s, "X"));
s.Attach(new ConcreteObserver(s, "Y"));
s.Attach(new ConcreteObserver(s, "Z"));
s.SubjectState = "ABC";
s.Notify(); ``` 不足:尽管已经用了依赖倒换原则,但是“抽象通知者”还是依赖“抽象观察者”,也就是说,万一没有了抽象观察者这样的接口,通知的功能就完成不了。此外,每个具体的观察者不一定就是调用相同的“更新”方法。 改进(事件委托实现):委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。一个委托可以搭载多个方法,所有方法被依次唤起,并且可以使得委托对象所搭载的方法并不需要属于同一个类。不过委托对象所搭载的方法必须具有相同的原型和形式。
抽象工厂
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。此外,它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
// 抽象工厂使产品类型、工厂类型(实际还是对应不同的产品类型)两个维度都可以扩展
abstract class AbstractFactory
{
public abstract AbstractProductA CreateProductA();
public abstract AbstractProductB CreateProductB();
}
class ConcreteFactory1 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA1();
}
public override AbstractProductB CreateProductB()
{
return new ProductB1();
}
}
class ConcreteFactory2 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA2();
}
public override AbstractProductB CreateProductB()
{
return new ProductB2();
}
}
abstract class AbstractProductA
{
}
abstract class AbstractProductB
{
public abstract void Interact(AbstractProductA a);
}
class ProductA1 : AbstractProductA
{
}
class ProductB1 : AbstractProductB
{
public override void Interact(AbstractProductA a)
{
Console.WriteLine(this.GetType().Name +
" interacts with " + a.GetType().Name);
}
}
class ProductA2 : AbstractProductA
{
}
class ProductB2 : AbstractProductB
{
public override void Interact(AbstractProductA a)
{
Console.WriteLine(this.GetType().Name +
" interacts with " + a.GetType().Name);
}
}
class Client
{
private AbstractProductA AbstractProductA;
private AbstractProductB AbstractProductB;
// Constructor
public Client(AbstractFactory factory)
{
AbstractProductB = factory.CreateProductB();
AbstractProductA = factory.CreateProductA();
}
public void Run()
{
AbstractProductB.Interact(AbstractProductA);
}
}
static void Main(string[] args)
{
AbstractFactory factory1 = new ConcreteFactory1();
Client c1 = new Client(factory1);
c1.Run();
AbstractFactory factory2 = new ConcreteFactory2();
Client c2 = new Client(factory2);
c2.Run();
}
所有在用简单工厂的地方,都可以考虑用反射技术来去除switch或if,解除分支判断带来的耦合。 反射的基本格式:Assembly.Load(“程序集名称”).CreateInstance(“命名空间.类名称”);因为是字符串,所以可以用变量来处理,也可以根据需要更换。
状态模式
状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来是改变了其类。 状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,就没有必要这么做了。 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。 (1)State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为。
abstract class State
{
public abstract void Handle(Context context);
}
(2)ConcreteState类,每一个子类实现一个与Context的一个状态相关的行为。
class ConcreteStateA : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateB();// 设置ConcreteStateA的下一个状态是ConcreteStateB
}
}
class ConcreteStateB : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateA();
}
}
(3)Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态。
class Context
{
private State state;
public Context(State state)
{
this.state = state;
}
public State State
{
get
{
return state;
}
set
{
state = value;
Console.WriteLine("当前状态:" + state.GetType().Name);
}
}
public void Request() //对请求做处理,并设置下一状态
{
state.Handle(this);
}
}
(4)客户端代码。
Context c = new Context(new ConcreteStateA());
c.Request();
c.Request();
c.Request();
c.Request();
适配器模式
适配器模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式包括类适配器模式和对象适配器模式,类适配器模式需要支持多重继承。
(1)Target类,是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
java
class Target
{
public virtual void Request()
{
Console.WriteLine("普通请求");
}
}
(2)Adaptee,需要适配的类。
class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("特殊请求");
}
}
```
(3)Adapter,通过在内部包装一个Adaptee对象,把源接口转换成目标接口。
```java
class Adapter : Target
{
private Adaptee adaptee = new Adaptee();
public override void Request()
{
adaptee.SpecificRequest();
}
}
```
(4)客户端代码:
```java
Target target = new Adapter();
target.Request();
```
## 备忘录模式
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。
(1)Originator:
```java
class Originator
{
private string state;
public string State
{
get { return state; }
set { state = value; }
}
public Memento CreateMemento()
{
return (new Memento(state));
}
public void SetMemento(Memento memento)
{
state = memento.State;
}
public void Show()
{
Console.WriteLine("State=" + state);
}
}
```
(2)Memento,负责存储Originator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento。备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。
```java
class Memento
{
private string state;
public Memento(string state)
{
this.state = state;
}
public string State
{
get { return state; }
}
}
```
(3)Caretaker,负责保存好备忘录Memento,不能对备忘录的内容进行检查或操作。
```java
class Caretaker
{
private Memento memento;
public Memento Memento
{
get { return memento; }
set { memento = value; }
}
}
```
(4)客户端代码:
```java
Originator o = new Originator();
o.State = "On";
o.Show();
Caretaker c = new Caretaker();
c.Memento = o.CreateMemento();
o.State = "Off";
o.Show();
o.SetMemento(c.Memento);
o.Show();
组合模式
组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 当需求中是体现部分与整体层次的结构时,或者希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。 (1)Component为组合中的对象声明接口,实现所有类共有接口的默认行为。
abstract class Component
{
protected string name;
public Component(string name)
{
this.name = name;
}
public abstract void Add(Component c);
public abstract void Remove(Component c);
public abstract void Display(int depth);
}
(2)Leaf在组合中表示叶节点对象,叶节点没有子节点。
class Leaf : Component
{
public Leaf(string name)
: base(name)
{ }
//虽然对叶子的添加删除操作没有意义,但是这样可以实现透明处理。
public override void Add(Component c)
{
Console.WriteLine("Cannot add to a leaf");
}
public override void Remove(Component c)
{
Console.WriteLine("Cannot remove from a leaf");
}
public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
}
}
(3)Composite定义有枝节点行为,用来存储子部件。
class Composite : Component
{
private List<Component> children = new List<Component>();
public Composite(string name)
: base(name)
{ }
public override void Add(Component c)
{
children.Add(c);
}
public override void Remove(Component c)
{
children.Remove(c);
}
public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
foreach (Component component in children)
{
component.Display(depth + 2);
}
}
}
(4)客户端代码:
Composite root = new Composite("root");
root.Add(new Leaf("Leaf A"));
root.Add(new Leaf("Leaf B"));
Composite comp = new Composite("Composite X");
comp.Add(new Leaf("Leaf XA"));
comp.Add(new Leaf("Leaf XB"));
root.Add(comp);
Composite comp2 = new Composite("Composite XY");
comp2.Add(new Leaf("Leaf XYA"));
comp2.Add(new Leaf("Leaf XYB"));
comp.Add(comp2);
root.Add(new Leaf("Leaf C"));
Leaf leaf = new Leaf("Leaf D");
root.Add(leaf);
root.Remove(leaf);
root.Display(1);
迭代器模式
迭代器模式:提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。 (1)Iterator:迭代器抽象类,之所以要抽象,是因为可能有多种不同的遍历方式。
abstract class Iterator
{
public abstract object First();
public abstract object Next();
public abstract bool IsDone();
public abstract object CurrentItem();
}
```
(2)Aggregate:聚集抽象类
```java
abstract class Aggregate
{
public abstract Iterator CreateIterator();
}
```
(3)ConcreteIterator:具体迭代器类,继承Iterator
```java
class ConcreteIterator : Iterator
{
private ConcreteAggregate aggregate;
private int current = 0;
public ConcreteIterator(ConcreteAggregate aggregate)
{
this.aggregate = aggregate;
}
public override object First()
{
return aggregate[0];
}
public override object Next()
{
object ret = null;
current++;
if (current < aggregate.Count)
{
ret = aggregate[current];
}
return ret;
}
public override object CurrentItem()
{
return aggregate[current];
}
public override bool IsDone()
{
return current >= aggregate.Count ? true : false;
}
}
```
(4)ConcreteAggregate:具体聚集类
```java
class ConcreteAggregate : Aggregate
{
private IList<object> items = new List<object>();
public override Iterator CreateIterator()
{
return new ConcreteIterator(this);
}
public int Count
{
get { return items.Count; }
}
public object this[int index]
{
get { return items[index]; }
set { items.Insert(index, value); }
}
}
(5)客户端代码:
ConcreteAggregate a = new ConcreteAggregate();
a[0] = "大鸟";
a[1] = "小菜";
a[2] = "行李";
a[3] = "老外";
a[4] = "公交内部员工";
a[5] = "小偷";
Iterator i = new ConcreteIterator(a);
object item = i.First();
while (!i.IsDone())
{
Console.WriteLine("{0} 请买车票!", i.CurrentItem());
i.Next();
}
单例模式
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。即,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。简单来说就是对唯一实例的受控访问。 (1)Singleton类:
class Singleton
{
private static Singleton instance;
private static readonly object syncRoot = new object();
private Singleton()
{
}
public static Singleton GetInstance()
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
(2)客户端代码:
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if (s1 == s2)
{
Console.WriteLine("Objects are the same instance");
}
桥接模式
桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立的变化。其实就是实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。 (1)Implementor类:
abstract class Implementor
{
public abstract void Operation();
}
(2)ConcreteImplementorA和ConcreteImplementorB等派生类:
class ConcreteImplementorA : Implementor
{
public override void Operation()
{
Console.WriteLine("具体实现A的方法执行");
}
}
class ConcreteImplementorB : Implementor
{
public override void Operation()
{
Console.WriteLine("具体实现B的方法执行");
}
}
(3)Abstraction类:
class Abstraction
{
protected Implementor implementor;
public void SetImplementor(Implementor implementor)
{
this.implementor = implementor;
}
public virtual void Operation()
{
implementor.Operation();
}
}
(4)RefinedAbstraction类:
class RefinedAbstraction : Abstraction
{
public override void Operation()
{
implementor.Operation();
}
}
(5)客户端实现:
Abstraction ab = new RefinedAbstraction();
ab.SetImplementor(new ConcreteImplementorA());
ab.Operation();
ab.SetImplementor(new ConcreteImplementorB());
ab.Operation();
Console.Read();
命令模式
命令模式:将一个请求封装为一个对象,从而使得可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。 (1)Command类,用来声明执行操作的接口:
abstract class Command
{
protected Receiver receiver;
public Command(Receiver receiver)
{
this.receiver = receiver;
}
abstract public void Execute();
}
(2)ConcreteCommand类,将一个接受者对象绑定于一个动作,调用接收者相应的操作,以实现Excute ```java class ConcreteCommand : Command { public ConcreteCommand(Receiver receiver) : base(receiver) { }
public override void Execute()
{
receiver.Action();
}
}
``` (3)Invoker类,要求该命令执行这个请求: ```java
class Invoker
{
private Command command;
public void SetCommand(Command command)
{
this.command = command;
}
public void ExecuteCommand()
{
command.Execute();
}
} ``` (4)Receiver类,知道如何实施与执行一个与请求相关的操作,任何类都有可能作为一个接收者:
```java
class Receiver
{
public void Action()
{
Console.WriteLine("执行请求!");
}
}
``` (5)客户端代码,创建一个具体命令对象并设定它的接收者:
Receiver r = new Receiver();
Command c = new ConcreteCommand(r);
Invoker i = new Invoker();
i.SetCommand(c);
i.ExecuteCommand(); 命令模式的优点:
1)能够较容易地设计一个命令队列;
2)在需要的情况下可以较容易地将命令写入日志;
3)允许接收请求的一方决定是否要否决请求;
4)可以容易地实现对请求的撤销和重做;
5)由于加入新的具体命令不影响其他的类,因此增加新的具体命令很容易;
6)最关键的一点:命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
职责链模式
职责链模式:使多个对象都有机会处理请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。这就使得接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。 (1)Handler类,定义一个处理请求的接口;
abstract class Handler
{
protected Handler successor; // 维护一个同类型的引用,用于链式传递请求
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void HandleRequest(int request);
}
(2)ConcreteHandler类,具体处理者类,处理它所负责的请求.可访问它的后继者。
class ConcreteHandler1 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 0 && request < 10)
{
Console.WriteLine("{0} 处理请求 {1}",this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
class ConcreteHandler2 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 10 && request < 20)
{
Console.WriteLine("{0} 处理请求 {1}",this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
class ConcreteHandler3 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 20 && request < 30)
{
Console.WriteLine("{0} 处理请求 {1}",this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
(3)客户端代码:
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();
Handler h3 = new ConcreteHandler3();
h1.SetSuccessor(h2);
h2.SetSuccessor(h3);
int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };
foreach (int request in requests)
{
h1.HandleRequest(request);
}
中介者模式
中介者模式:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 (1)Mediator类,抽象中介者:
abstract class Mediator
{
public abstract void Send(string message, Colleague colleague);
}
(2)Colleague:抽象同事类:
abstract class Colleague
{
protected Mediator mediator;
public Colleague(Mediator mediator)
{
this.mediator = mediator;
}
}
(3)ConcreteMediator类:
class ConcreteMediator : Mediator
{
private ConcreteColleague1 colleague1;
private ConcreteColleague2 colleague2;
public ConcreteColleague1 Colleague1
{
set { colleague1 = value; }
}
public ConcreteColleague2 Colleague2
{
set { colleague2 = value; }
}
public override void Send(string message, Colleague colleague)
{
if (colleague == colleague1)
{
colleague2.Notify(message);
}
else
{
colleague1.Notify(message);
}
}
}
(4)具体同事类:
class ConcreteColleague1 : Colleague
{
public ConcreteColleague1(Mediator mediator)
: base(mediator)
{ }
public void Send(string message)
{
mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine("同事1得到信息:" + message);
}
}
class ConcreteColleague2 : Colleague
{
public ConcreteColleague2(Mediator mediator)
: base(mediator)
{ }
public void Send(string message)
{
mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine("同事2得到信息:" + message);
}
}
(5)客户端调用:
ConcreteMediator m = new ConcreteMediator();
ConcreteColleague1 c1 = new ConcreteColleague1(m);
ConcreteColleague2 c2 = new ConcreteColleague2(m);
m.Colleague1 = c1;
m.Colleague2 = c2;
c1.Send("吃过饭了吗?");
c2.Send("没有呢,你打算请客?");
享元模式
享元模式:运用共享技术有效地支持大量细粒度的对象。 如果发现某个对象的生成了大量细粒度的实例,并且这些实例除了几个参数外基本是相同的,如果把那些共享参数移到类外面,在方法调用时将他们传递进来,就可以通过共享大幅度减少单个实例的数目。 (1)Flyweight类:
abstract class Flyweight
{
public abstract void Operation(int extrinsicstate);
}
(2)ConcreteFlyweight类:
class ConcreteFlyweight : Flyweight
{
public override void Operation(int extrinsicstate)
{
Console.WriteLine("具体Flyweight:" + extrinsicstate);
}
}
(3)UnsharedConcreteFlyweight类:
class UnsharedConcreteFlyweight : Flyweight
{
public override void Operation(int extrinsicstate)
{
Console.WriteLine("不共享的具体Flyweight:" + extrinsicstate);
}
}
(4)FlyweightFactory:
class FlyweightFactory
{
private Hashtable flyweights = new Hashtable();
//不一定非要事先生成对象,也可以需要时根据判断是否为NULL再进行实例化
public FlyweightFactory()
{
flyweights.Add("X", new ConcreteFlyweight());
flyweights.Add("Y", new ConcreteFlyweight());
flyweights.Add("Z", new ConcreteFlyweight());
}
public Flyweight GetFlyweight(string key)
{
return ((Flyweight)flyweights[key]);
}
}
(5)客户端代码:
int extrinsicstate = 22; //代码外部状态
FlyweightFactory f = new FlyweightFactory();
Flyweight fx = f.GetFlyweight("X");
fx.Operation(--extrinsicstate);
Flyweight fy = f.GetFlyweight("Y");
fy.Operation(--extrinsicstate);
Flyweight fz = f.GetFlyweight("Z");
fz.Operation(--extrinsicstate);
UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight();
uf.Operation(--extrinsicstate);
内部状态与外部状态:在享元对象内部,并且不会随环境改变而改变的共享部分,称为享元对象的内部状态,而随环境改变而改变的、不可以共享的状态就是外部状态。也就是说,享元模式Flyweight执行时所需的状态是有内部的也有可能有外部的。内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。
解释器模式
解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。 (1)AbstractExpression:
abstract class AbstractExpression
{
public abstract void Interpret(Context context);
}
(2)TerminalExpression:
class TerminalExpression : AbstractExpression
{
public override void Interpret(Context context)
{
Console.WriteLine("终端解释器");
}
}
(3)NonterminalExpression:
class NonterminalExpression : AbstractExpression
{
public override void Interpret(Context context)
{
Console.WriteLine("非终端解释器");
}
}
(4)Context:
class Context
{
private string input;
public string Input
{
get { return input; }
set { input = value; }
}
private string output;
public string Output
{
get { return output; }
set { output = value; }
}
}
(5)客户端代码:
Context context = new Context();
IList<AbstractExpression> list = new List<AbstractExpression>();
list.Add(new TerminalExpression());
list.Add(new NonterminalExpression());
list.Add(new TerminalExpression());
list.Add(new TerminalExpression());
foreach (AbstractExpression exp in list)
{
exp.Interpret(context);
}
解释器模式使得可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,可使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。 不足:解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理更好。
访问者模式
访问者模式:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。访问者的优势在于增加新的操作很容易,因为这就意味着增加一个新的访问者。不足在于,使增加新的数据结构变得困难了。 (1)Visitor类:
abstract class Visitor
{
public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);
public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
}
(2)ConcreteVisitor类:
class ConcreteVisitor1 : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);
}
}
class ConcreteVisitor2 : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);
}
}
(3)Element类:
abstract class Element
{
public abstract void Accept(Visitor visitor);
}
(4)ConcreteElement类:
class ConcreteElementA : Element
{
// 被访问元素定义Accept操作来接受一个Visitor,使该Visitor指向当前元素后,调用Visitor的访问方法
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementA(this);
}
public void OperationA()
{ }
}
class ConcreteElementB : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementB(this);
}
public void OperationB()
{ }
}
(5)ObjectStucture类:
class ObjectStructure
{
private IList<Element> elements = new List<Element>();
public void Attach(Element element)
{
elements.Add(element);
}
public void Detach(Element element)
{
elements.Remove(element);
}
public void Accept(Visitor visitor)
{
foreach (Element e in elements)
{
e.Accept(visitor);
}
}
}
(6)客户端代码:
ObjectStructure o = new ObjectStructure();
o.Attach(new ConcreteElementA());
o.Attach(new ConcreteElementB());
ConcreteVisitor1 v1 = new ConcreteVisitor1();
ConcreteVisitor2 v2 = new ConcreteVisitor2();
o.Accept(v1);
o.Accept(v2);