主题 | 概要 |
---|---|
设计模式 | 大话设计模式读书笔记 |
编辑 | 时间 |
新建 | 20170423 |
序号 | 参考资料 |
1 | 大话设计模式 |
重新看了一遍设计模式,除了一些已经特别熟悉的模式,都自己敲了一遍代码,有些豁然开朗的感觉。
策略模式(Strategy)
类型:行为型
使用场景:当一个类的行为或其算法可以在运行时更改。定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。可以消除if…else…所带来的复杂和难以维护。
这个图还是比较简单的,转换成代码:
抽象策略类:
namespace DesignModeDemo.Stragegy {
abstract class Strategy {
public abstract void algorithemInterface();
}
}
具体策略类:
namespace DesignModeDemo.Stragegy {
class ConcreteStartegyA:Strategy {
public override void algorithemInterface()
{
Console.WriteLine("Strategy A");
}
}
}
namespace DesignModeDemo.Stragegy {
class ConcreteStartegyB : Strategy {
public override void algorithemInterface()
{
Console.WriteLine("Strategy B");
}
}
}
namespace DesignModeDemo.Stragegy {
class ConcreteStrategyC:Strategy {
public override void algorithemInterface()
{
Console.WriteLine("Strategy C");
}
}
}
上下文:
namespace DesignModeDemo.Stragegy
{
class Context
{
private Strategy strategy;
public Context(Strategy strategy)
{
this.strategy = strategy;
}
public void contextInterface()
{
strategy.algorithemInterface();
}
}
}
客户端代码:
static void Main(string[] args)
{
Context ctA = new Context(new ConcreteStartegyA());
ctA.contextInterface();
Context ctB = new Context(new ConcreteStartegyB());
ctB.contextInterface();
Context ctC = new Context(new ConcreteStrategyC());
ctC.contextInterface();
Console.Read();
}
Story:
小菜实现一个商场收银系统,有很多不同的打折策略,并结合工厂方法:
几种策略:
namespace DesignModeDemo.Stragegy {
abstract class CashSuper {
public abstract void acceptCash();
}
}
namespace DesignModeDemo.Stragegy {
class CashNormal:CashSuper {
public override void acceptCash()
{
Console.WriteLine("CashNormal");
}
}
}
namespace DesignModeDemo.Stragegy {
class CashRebate:CashSuper {
public override void acceptCash()
{
Console.WriteLine("CashRebate");
}
}
}
上下文:
namespace DesignModeDemo.Stragegy
{
class CashContext
{
private CashSuper cashStrategy;
public CashContext(CashSuper cashStrategy)
{
this.cashStrategy = cashStrategy;
}
public CashContext(string cashStrategy) //--工厂模式,隐藏具体策略细节,更好
{
switch (cashStrategy)
{
case "normal":
this.cashStrategy = new CashNormal();
break;
case "rebate":
this.cashStrategy = new CashRebate();
break;
default:
break;
}
}
public void getResult()
{
cashStrategy.acceptCash();
}
}
}
客户端代码:
static void Main(string[] args)
{
CashContext ccA = new CashContext("normal");
ccA.getResult();
CashContext ccB = new CashContext("rebate");
ccB.getResult();
Console.Read();
}
装饰器模式(Decorator Pattern)
类型:结构型
使用场景:当需要向一个现有对象添加新的功能时,如果使用继承方式,随着功能的扩展,子类会很膨胀。而使用装饰器给一个对象添加一些额外的功能,比生成子类更为灵活。
这个图刚开始,不易理解的点儿是Decorator继承了Component,同时Decorator又维护了一个对Component的引用。
转换成代码:
namespace DesignModeDemo.Decorator {
abstract class Component {
public abstract void operation();
}
}
namespace DesignModeDemo.Decorator {
class ConcreteComponent:Component {
public override void operation()
{
Console.WriteLine("具体对象的操作");
}
}
}
装饰者,继承自一个组件,并维护一个组件的引用:
namespace DesignModeDemo.Decorator
{
abstract class Decorator:Component
{
private Component component;
public void setComponent(Component component)
{
this.component = component;
}
public override void operation()
{
if (component!=null)
{
component.operation();
}
}
}
}
给组件添加特有的装饰行为:
namespace DesignModeDemo.Decorator
{
class ConcerateDecoratorA:Decorator
{
private void addBeave() { Console.WriteLine("ConcerateDecoratorA"); }//--A类装饰器特有
public override void operation()
{
base.operation();
addBeave();
}
}
}
namespace DesignModeDemo.Decorator
{
class ConcerateDecoratorB:Decorator
{
private void addState() { Console.WriteLine("ConcerateDecoratorB"); }//--B类装饰器特有
public override void operation()
{
base.operation();
addState();
}
}
}
客户端代码:
static void Main(string[] args)
{
ConcreteComponent comp = new ConcreteComponent();
ConcerateDecoratorA deA = new ConcerateDecoratorA();
ConcerateDecoratorB deB = new ConcerateDecoratorB();
deA.setComponent(comp);
deB.setComponent(deA);
deB.operation(); //--deB包装了 addState和addBeave功能
Console.Read();
}
Story:
小菜实现一个可以给人搭配不同的服务的系统。
第一版本结构图:
所有功能放在一起。
第二版本结构图:
人与服饰分离,并且把服饰抽象出来。
第三版本结构图:
人与服饰分离,并且把服饰抽象出来。
具体实现:
人为具体组件,但这里直接是具体类,没有用接口:
namespace DesignModeDemo.Decorator
{
class Person
{
private string name;
public Person() { }
public Person(string name)
{
this.name = name;
}
public virtual void show()
{
Console.WriteLine("装扮的{0}",name);
}
}
}
服饰为装饰类的基类:
namespace DesignModeDemo.Decorator
{
class Finery:Person
{
private Person person;
public void decorator(Person person)
{
this.person = person;
}
public override void show()
{
if(person!=null)
{
person.show();
}
}
}
}
两个具体的装饰类,包装了自己的功能:
namespace DesignModeDemo.Decorator {
class TShirts:Finery {
public override void show()
{
Console.WriteLine("Add TShirts decoreator");
base.show();
}
}
}
namespace DesignModeDemo.Decorator {
class BigTrouser:Finery {
public override void show()
{
Console.WriteLine("Add BigTrouser decoreator");
base.show();
}
}
}
客户端调用:
static void Main(string[] args)
{
Person person = new Person("小菜");
TShirts ts = new TShirts();
BigTrouser bt = new BigTrouser();
ts.decorator(person);
bt.decorator(ts);
bt.show();
Console.Read();
}
运行结果:
在原有功能上,增加了两个装饰类自己包装的功能。
代理模式
类型:结构型
使用场景:为其它对象提供一种代理以控制对这个对象的访问。主要解决在直接访问对象时带来的问题。比如智能指针、远程代理等场景。
注意这里,Proxy与RealSubject共用相同的接口。
抽像Subject
namespace DesignModeDemo.proxy {
abstract class Subject {
public abstract void request();
}
}
具体Subject:
namespace DesignModeDemo.proxy {
class RealSubject:Subject {
public override void request()
{
Console.WriteLine("RealSubject");
}
}
}
代理类:
namespace DesignModeDemo.proxy
{
class Proxy:Subject
{
private Subject subject;
public override void request()
{
if(null==subject)
{
subject = new RealSubject();
}
subject.request();
}
}
}
客户端:
static void Main(string[] args)
{
Proxy proxy = new Proxy();
proxy.request();
Console.Read();
}
Story:
追女孩儿的故事,追求者通过代理人来追女孩,追求者应该和女孩不相识,所有活动都通过代理来进行。
女孩:
namespace DesignModeDemo.proxy
{
class SchoolGirl
{
private string name;
public SchoolGirl(string name)
{
this.name = name;
}
public string Name { get { return name; } }
}
}
送礼物接口:
namespace DesignModeDemo.proxy {
interface IGiveGift {
void giveDolls();
void giveFlowers();
void giveChocolate();
}
}
追求者:
namespace DesignModeDemo.proxy
{
class Pursuit:IGiveGift
{
private SchoolGirl mm;
public Pursuit(SchoolGirl mm)
{
this.mm = mm;
}
public void giveDolls()
{
Console.WriteLine(mm.Name+" give your dolls");
}
public void giveFlowers()
{
Console.WriteLine(mm.Name + " give your flowrs");
}
public void giveChocolate()
{
Console.WriteLine(mm.Name + " give your chocolate");
}
}
}
追求者代理:
namespace DesignModeDemo.proxy
{
class PursuitProxy:IGiveGift
{
Pursuit pursuit;
public PursuitProxy(SchoolGirl mm)
{
pursuit = new Pursuit(mm);
}
public void giveDolls()
{
pursuit.giveDolls();
}
public void giveFlowers()
{
pursuit.giveFlowers() ;
}
public void giveChocolate()
{
pursuit.giveChocolate();
}
}
}
原型模式
类型:创建型
使用场景:直接通过拷贝原型,创建重复的对象。实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。
转换成代码:
抽象原型:
namespace DesignModeDemo.prototype
{
abstract class Prototype
{
private string id;
public Prototype(string id)
{
this.id = id;
}
public string ID
{
get { return id; }
}
public abstract Prototype clone();
}
}
具体原型:
namespace DesignModeDemo.prototype
{
class ConcretePrototype1:Prototype
{
public ConcretePrototype1(string id):base(id)
{
}
public override Prototype clone()
{
return this.MemberwiseClone() as Prototype;
}
}
}
客户端代码:
static void Main(string[] args)
{
ConcretePrototype1 cc = new ConcretePrototype1("cc");
ConcretePrototype1 dd = cc.clone() as ConcretePrototype1;
Console.WriteLine("Cloned:" + dd.ID);
Console.Read();
}
Story:
招聘网站上,每个人可以创建多份简历,可以使用原型模式,直接clone一份简历,只需修改想要修改的信息。clone时要注意浅复制与深层复制的区别。
工作经历类:
namespace DesignModeDemo.prototype
{
class WorkExperience:ICloneable
{
private string workDate;
private string workCompany;
public string WorkDate
{
get
{
return workDate;
}
set
{
workDate = value;
}
}
public string WorkCompany
{
get
{
return workCompany;
}
set
{
workCompany = value;
}
}
public object Clone()
{
return this.MemberwiseClone() as object;
}
}
}
简历类:
namespace DesignModeDemo.prototype
{
class Resume:ICloneable
{
private string name;
private string age;
private string sex;
private WorkExperience workExperience;
public Resume(string name)
{
this.name = name;
workExperience = new WorkExperience();
}
//--私有构造函数,clone工作经历
private Resume(WorkExperience workExperience)
{
this.workExperience = workExperience.Clone() as WorkExperience;
}
public void setPersonInfo(string age,string sex)
{
this.age = age;
this.sex = sex;
}
public void setWorkExperience(string workDate,string workCompany)
{
workExperience.WorkDate = workDate;
workExperience.WorkCompany = workCompany;
}
public void display()
{
Console.WriteLine("name={0},sex={1},age={2}",name,sex,age);
Console.WriteLine("Work experience,time={0},company={1}", workExperience.WorkDate,workExperience.WorkCompany);
}
public object Clone()
{
Resume newResume = new Resume(workExperience); //--先clone 工作经历
newResume.name = name;
newResume.age = age;
newResume.sex = sex;
return newResume;
}
}
}
客户端:
static void Main(string[] args)
{
Resume a = new Resume("daliao");
a.setPersonInfo("25", "man");
a.setWorkExperience("2years", "zte");
Resume b = a.Clone() as Resume;
b.setWorkExperience("2years", "huawei");
a.display();
b.display();
Console.Read();
}
输出:
模版模式
类型:行为型
使用场景:在抽象类中定义一个操作中算法的骨架,而将一些步骤延迟到子类中,子类可以按需要重写方法实现,模版方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
转换成代码:
抽象类:
namespace DesignModeDemo.templatemethod
{
abstract class AbstractClass
{
//--抽象方法,延迟到子类中实现
public abstract void primitiveOpertion1();
public abstract void primitiveOpertion2();
//--算法骨架,可以调用抽象方法
public void templateMethod()
{
primitiveOpertion1();
primitiveOpertion2();
}
}
}
具体类A:
namespace DesignModeDemo.templatemethod
{
class ConcerateClassA:AbstractClass
{
public override void primitiveOpertion1()
{
Console.WriteLine("ConcerateClassA:primitiveOpertion1");
}
public override void primitiveOpertion2()
{
Console.WriteLine("ConcerateClassA:primitiveOpertion2");
}
}
}
具体类B:
namespace DesignModeDemo.templatemethod
{
class ConcerateClassB:AbstractClass
{
public override void primitiveOpertion1()
{
Console.WriteLine("ConcerateClassB:primitiveOpertion1");
}
public override void primitiveOpertion2()
{
Console.WriteLine("ConcerateClassB:primitiveOpertion2");
}
}
}
客户端代码:
static void Main(string[] args)
{
AbstractClass c;
c = new ConcerateClassA();
c.templateMethod();
c = new ConcerateClassB();
c.templateMethod();
Console.Read();
}
Story:
考试试卷,试题不变,答题步骤不变,每个考生的答案不相同,可以采用此模式。
试卷:
namespace DesignModeDemo.templatemethod
{
abstract class TestPaper
{
public void question1()
{
Console.WriteLine("how old are you? a:20;b:30;c:40");
Console.WriteLine("answer is :" + answer1());
}
protected abstract string answer1();
}
}
考生A答案:
namespace DesignModeDemo.templatemethod {
class TestPaperA:TestPaper {
protected override string answer1()
{
return "b";
}
}
}
考生B答案:
namespace DesignModeDemo.templatemethod {
class TestPaperB:TestPaper {
protected override string answer1()
{
return "c";
}
}
}
客户端:
static void Main(string[] args)
{
Console.WriteLine("StudentA answer");
TestPaperA tpa = new TestPaperA();
tpa.question1();
Console.WriteLine("StudentB answer");
TestPaperB tpb = new TestPaperB();
tpb.question1();
Console.Read();
}
输出:
外观模式
类型:结构型
使用场景:为子系统的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。它隐藏了系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。
用外观模式的时机:首先,在设计初期阶段,应该要有意识的将不同的两个层分离,层与层之间建立facade;其次,在开发阶段,子系统会越来越复杂,增加外观facade可以提供一个简单的接口,减少它们之间的依赖。最后,在维护复杂代码时,也可以把遗留代码增加一个清晰的简单接口。如:
转换成代码:
已存在的子系统:
namespace DesignModeDemo.facade {
class SubSystemOne {
public void methodOne()
{
Console.WriteLine("SubSystemOne:methodOne");
}
}
class SubSystemTwo {
public void methodTwo()
{
Console.WriteLine("SubSystemTwo:methodTwo");
}
}
}
Facade:
namespace DesignModeDemo.facade
{
class Facade
{
SubSystemOne one;
SubSystemTwo two;
public Facade()
{
one = new SubSystemOne();
two = new SubSystemTwo();
}
//--提供对外接口,隐藏细节
public void methodA()
{
one.methodOne();
two.methodTwo();
}
}
}
客户端代码:
static void Main(string[] args)
{
Facade fa = new Facade();
fa.methodA();
Console.Read();
}
Story:
全民投资,炒股、炒房、炒国债,可以自己亲力亲为,也可以交给一家基金公司打理,把操作细节留给基金公司,客户只要与基金公司联系。
地产:
namespace DesignModeDemo.facade
{
class Realty
{
public void buy()
{
Console.WriteLine("buy Realty");
}
public void sell()
{
Console.WriteLine("sell Realty");
}
}
}
股票:
namespace DesignModeDemo.facade
{
class Stock
{
public void buy()
{
Console.WriteLine("buy stock");
}
public void sell()
{
Console.WriteLine("sell stock");
}
}
}
国债:
namespace DesignModeDemo.facade
{
class NationalDept
{
public void buy()
{
Console.WriteLine("buy NationalDept");
}
public void sell()
{
Console.WriteLine("sell NationalDept");
}
}
}
基金,隐藏了所有理财方式:
namespace DesignModeDemo.facade
{
class Found
{
private Stock stock;
private Realty realty;
private NationalDept natioalDept;
public Found()
{
stock = new Stock();
realty = new Realty();
natioalDept = new NationalDept();
}
public void buy()
{
stock.buy();
realty.buy();
natioalDept.buy();
}
public void sell()
{
stock.sell();
realty.sell();
natioalDept.sell();
}
}
}
客户端代码:
static void Main(string[] args)
{
Found found = new Found();
found.buy();
found.sell();
Console.Read();
}
输出结果:
建造者模式
类型:创建型
使用场景:
使用多个简单的对象,一步一步构建成一个复杂的对象。将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
这里面有三个角色,指挥者根据用户的需求构建对象;构造者用来装配和构造各个部件;产品是具体的构建部件。
转换成代码:
产品,包括了一个部件列表:
namespace DesignModeDemo.builder
{
class Product
{
IList<string> part = new List<string>();//--产品部件
public void add(string partItem)
{
part.Add(partItem);
}
public void show()
{
Console.WriteLine("build product");
foreach (string p in part)
{
Console.WriteLine(p);
}
}
}
}
抽象Builder类:
namespace DesignModeDemo.builder
{
abstract class Builder
{
public abstract void buildPartA();
public abstract void buildPartB();
public abstract Product getResult();
}
}
具体建造者类A:
namespace DesignModeDemo.builder
{
class ConcreteBuildA:Builder
{
private Product product;
public ConcreteBuildA()
{
product = new Product();
}
public override void buildPartA()
{
product.add("ConcreteBuildA:Product A");
}
public override void buildPartB()
{
product.add("ConcreteBuildA:Product B");
}
public override Product getResult()
{
return product;
}
}
}
具体建造者B:
namespace DesignModeDemo.builder
{
class ConcereteBuildB:Builder
{
private Product product;
public ConcereteBuildB()
{
product = new Product();
}
public override void buildPartA()
{
product.add("ConcereteBuildB:Product C");
}
public override void buildPartB()
{
product.add("ConcereteBuildB:Product D");
}
public override Product getResult()
{
return product;
}
}
}
指挥者:
namespace DesignModeDemo.builder {
class Director {
public void construct(Builder builder) //--指挥构造
{
builder.buildPartA();
builder.buildPartB();
}
}
}
客户端:
static void Main(string[] args)
{
Director director = new Director();
ConcreteBuildA buildA = new ConcreteBuildA();
ConcereteBuildB buildB = new ConcereteBuildB();
director.construct(buildA);
buildA.getResult().show();
director.construct(buildB);
buildB.getResult().show();
Console.Read();
}
输出:
Story:
画一个小人,为了避免缺胳膊少腿,可利用建造者模式,由于涉及到UI,不好在控制台实现一遍。
观察者模式
类型:行为型
使用场景:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
转换成代码:
观察者基类:
namespace DesignModeDemo.observer {
abstract class Observer {
public abstract void update();
}
}
具体观察者:
namespace DesignModeDemo.observer
{
class ConcerteObserver:Observer
{
private string name;
private ConcerteSubject concerteSubject; //--这里没有与具体主题解耦
public ConcerteObserver(string name, ConcerteSubject concerteSubject)
{
this.name = name;
this.concerteSubject = concerteSubject;
}
public override void update()
{
Console.WriteLine("Notify to :{0},Subject:{1} changed",name,concerteSubject.SubjectState);
}
public ConcerteSubject Subject
{
get { return concerteSubject; }
set { concerteSubject = value; }
}
}
}
基类主题:
namespace DesignModeDemo.observer
{
abstract class Subject
{
private IList<Observer> observers=new List<Observer>();
public void attach(Observer o)
{
observers.Add(o);
}
public void detach(Observer o)
{
observers.Remove(o);
}
public void notify()
{
foreach(Observer o in observers)
{
o.update();
}
}
}
}
具体主题:
namespace DesignModeDemo.observer {
class ConcerteSubject:Subject {
private string subjectState;//--具体主题状态
public string SubjectState
{
get
{
return subjectState;
}
set
{
subjectState = value;
}
}
}
}
客户端代码:
static void Main(string[] args)
{
ConcerteSubject cs = new ConcerteSubject();
cs.attach(new ConcerteObserver("X", cs));
cs.attach(new ConcerteObserver("Y", cs));
cs.attach(new ConcerteObserver("Z", cs));
cs.SubjectState = "new";
cs.notify();
Console.Read();
}
输出:
Story:
老板出去时,员工开始炒股票,老板回来时,前台发出通知,员工停止炒股票。
主题接口:
interface ISubject {
void attach(AbstractObserver o);
void detach(AbstractObserver o);
void notify();
string SubjectState
{
get;
set;
}
}
具体主题Boss,维护一个观察者列表:
class Boss : ISubject
{
private IList<AbstractObserver> observers = new List<AbstractObserver>();
private string state;
public string SubjectState
{
get
{
return state;
}
set
{
state = value;
}
}
public void attach(AbstractObserver o)
{
observers.Add(o);
}
public void detach(AbstractObserver o)
{
observers.Remove(o);
}
public void notify()
{
foreach (AbstractObserver o in observers)
{
o.update();
}
}
}
抽象观察者:
abstract class AbstractObserver
{
protected string name;
protected ISubject subject;
public AbstractObserver(string name, ISubject subject)
{
this.name = name;
this.subject = subject;
}
public abstract void update();
}
具体股票观察者:
class StockObserver : AbstractObserver
{
public StockObserver(string name, ISubject subject) : base(name, subject) { }
public override void update()
{
Console.WriteLine("Notify to :{0},Boss:{1} minutes arrive,stop stock", name, subject.SubjectState);
}
}
具体NBA观察者:
class NBAObserver : AbstractObserver
{
public NBAObserver(string name, ISubject subject) : base(name, subject) { }
public override void update()
{
Console.WriteLine("Notify to :{0},Boss:{1} minutes arrive,stop watch NBA", name, subject.SubjectState);
}
}
客户端代码:
static void Main(string[] args)
{
Boss bs = new Boss();
bs.attach(new NBAObserver("shao", bs));
bs.attach(new StockObserver("wang", bs));
bs.SubjectState = "5";
bs.notify();
Console.Read();
}
输出:
改进与不足:
当一个主题发生变化时,其实没法为每个观察者都去实现抽象观察者的接口,因为有些观察者早已被他们的制造商给封装了。解决此类问题的方法是使用事件委拖。
“看股票观察类”和“看NBA观察类”,去掉了父类“抽象观察者类”,并将update方法更名为各自适合的方法名。
主题接口,去掉了attach、detach方法:
interface ISubject {
void notify();
string SubjectState
{
get;
set;
}
}
Boss主题,使用委托代替维护的观察者列表。
class Boss : ISubject
{
public NotifyHandler notifyHandler=null;
private string state;
public delegate void NotifyHandler();
public string SubjectState
{
get
{
return state;
}
set
{
state = value;
}
}
public void notify()
{
notifyHandler();
}
}
股票观察者,不再实现抽象观察者的统一接口:
class StockObserver
{
private string name;
private ISubject sub;
public StockObserver(string name, ISubject sub) {
this.name = name;
this.sub = sub;
}
public void stopStock()
{
Console.WriteLine("Notify to :{0},Boss:{1} minutes arrive,stop stock", name, sub.SubjectState);
}
}
NBA观察者,也再实现抽象观察者的统一接口:
class NBAObserver
{
private string name;
private ISubject subject;
public NBAObserver(string name, ISubject subject)
{
this.name = name;
this.subject = subject;
}
public void stopNBA()
{
Console.WriteLine("Notify to :{0},Boss:{1} minutes arrive,stop watch NBA", name, subject.SubjectState);
}
}
客户端代码:
static void Main(string[] args)
{
Boss bs = new Boss();
bs.notifyHandler += new NBAObserver("shao", bs).stopNBA;
bs.notifyHandler += new StockObserver("wang", bs).stopStock;
bs.SubjectState = "5";
bs.notify();
Console.Read();
}
输出:
委托相当于C语言的函数指针,一个委托可以搭载多个对象,所有方法被依次唤起,委托对象所搭载的方法并不需要属于同一个类,也不限定方法的名称,只需方法具有相同的参数列表和返回值类型。
适配器模式
类型:结构型
使用场景:适配器模式作为两个不兼容的接口之间的桥梁。它结合了两个独立接口的功能。
比如.net中的DataAdapter,用作DataSet和数据源之间的适配器以便检索和保存数据。不同的数据源,都映射到Fill和Update来进行适配。
转换成代码:
被适配器类:
namespace DesignModeDemo.adapter {
class Adaptee {
public void specifiRequest()
{
Console.WriteLine("special request");
}
}
}
适配器目标:
namespace DesignModeDemo.adapter {
class Target {
public virtual void request()
{
Console.WriteLine("normal request");
}
}
}
适配器:
namespace DesignModeDemo.adapter {
class Adapter:Target {
private Adaptee adaptee = new Adaptee();
public override void request()
{
adaptee.specifiRequest();
}
}
}
客户端代码:
static void Main(string[] args)
{
Adapter ada = new Adapter();
ada.request();
Console.Read();
}
Story:
姚明去火箭打球时,需要翻译,这个翻译的功能就是一个适配器模式。
外藉中锋:
namespace DesignModeDemo.adapter
{
class ForeginCenter
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public void 进攻()
{
Console.WriteLine("外藉中锋{0},进攻",name);
}
public void 防守()
{
Console.WriteLine("外藉中锋{0},防守", name);
}
}
}
Player类:
namespace DesignModeDemo.adapter
{
abstract class Player
{
public abstract void attack();
public abstract void defense();
}
}
前锋:
namespace DesignModeDemo.adapter
{
class Forwards : Player
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public override void attack()
{
Console.WriteLine("前锋{0},进攻", name);
}
public override void defense()
{
Console.WriteLine("前锋{0},进攻", name);
}
}
}
翻译:
namespace DesignModeDemo.adapter
{
class Translator : Player
{
private ForeginCenter fc;
public Translator(string name)
{
fc = new ForeginCenter();
fc.Name = name;
}
public override void attack()
{
fc.进攻();
}
public override void defense()
{
fc.防守();
}
}
}
客户端代码:
static void Main(string[] args)
{
Forwards forwards = new Forwards();
forwards.Name = "麦迪";
forwards.attack();
forwards.defense();
Translator tran = new Translator("姚明");
tran.attack();
tran.defense();
Console.Read();
}
输出:
一点思考:
适配器模式和代理模式太相象了,他们最明显的区别是代理和被代理者实际上具有相同的接口,结构图如下:
可能由于某种原因,客户访问不到被代理者,所以利用代理间接访问。而适配器模式,是因为接口不同,后期维护或用到第三方库时作为一种统一的映射。
状态模式
类型:行为型
使用场景:当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
这个模式的困惑之处是,上下文Context引用了一个状态State,但同时会把Context自身作为参数传递给State,以使得具体State类中可以改变当前Context的状态。
转换成代码:
抽象状态类:
namespace DesignModeDemo.state {
abstract class State {
public abstract void handle(Context context);
}
}
具体类:
namespace DesignModeDemo.state {
class ConcreteStateA : State {
public override void handle(Context context)
{
Console.WriteLine("ConcreteStateA will be switch to ConcreteStateB");
context.State=new ConcreteStateB();
}
}
class ConcreteStateB: State {
public override void handle(Context context)
{
Console.WriteLine("ConcreteStateB will be switch to ConcreteStateA");
context.State = new ConcreteStateA();
}
}
}
上下文类:
namespace DesignModeDemo.state
{
class Context
{
private State state;
public Context(State state)
{
this.state = state;
}
public State State
{
get
{
return state;
}
set
{
state = value;
Console.WriteLine("Current state:"+state.GetType().Name);
}
}
public void request()
{
state.handle(this); //--调用当前状态的处理句柄,并把上下文传进去,以方便更改状态
}
}
}
客户端代码:
static void Main(string[] args)
{
ConcreteStateA stateA = new ConcreteStateA();
state.Context ct = new state.Context(stateA);
//--同一个调用,状态已经发生了改变
ct.request();
ct.request();
Console.Read();
}
输出:
Story:
程序员的工作时长,决定了他的工作效率。可以以时间为条件来判断他处于什么工作状态。
如,早上9点打了鸡血,晚上9点就很疲惫。
工作状态基类:
namespace DesignModeDemo.state {
abstract class WorkSateBase {
public abstract void writePrograme(Worker worker);
}
}
早、中、晚的工作状态:
class ForenoonState : WorkSateBase
{
public override void writePrograme(Worker worker)
{
if(worker.Hour<12)
{
Console.WriteLine("时间:{0},工作激情",worker.Hour);
}
else
{
worker.WorkState = new NoonState();
worker.writeProgram();
}
}
}
class NoonState : WorkSateBase
{
public override void writePrograme(Worker worker)
{
if (worker.Hour < 13)
{
Console.WriteLine("时间:{0},需吃饭", worker.Hour);
}
else
{
worker.WorkState = new AfternoonState();
worker.writeProgram();
}
}
}
class AfternoonState : WorkSateBase
{
public override void writePrograme(Worker worker)
{
if (worker.Hour < 18)
{
Console.WriteLine("时间:{0},快下班", worker.Hour);
}
else
{
Console.WriteLine("时间:{0},下班啦", worker.Hour);
worker.IsFinished = true;
worker.WorkState = new ForenoonState();//--重新开始,很重要
}
}
}
工作类:
class Worker
{
private int hour;
private bool isFinished;
private WorkSateBase workState;
public Worker(WorkSateBase workState)
{
this.WorkState = workState;
isFinished = false;
}
public void writeProgram()
{
WorkState.writePrograme(this); //--当前状态下写程序,并可能切换工作状态
}
public int Hour
{
get
{ return hour; }
set
{ hour = value; }
}
public bool IsFinished
{
get
{ return isFinished; }
set
{ isFinished = value;}
}
internal WorkSateBase WorkState
{
get
{ return workState; }
set
{ workState = value; }
}
}
客户端代码:
static void Main(string[] args)
{
Worker work = new Worker(new ForenoonState());
work.Hour = 10;
work.writeProgram();
work.Hour = 17;
work.writeProgram();
work.Hour = 19;
work.writeProgram();
work.Hour = 9;
work.writeProgram();
Console.Read();
}
输出:
备忘录模式
类型:行为型
使用场景:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
这里有三个角色:
Originator,发起者,负责记录当前时刻的某些属性到一个备忘录或者从备忘录中恢复。
Memento,备忘录,存储发起者的内部状态。
Caretaker,管理者,用来管理备忘录,相当于一个存取备忘录的容器。
转换成代码:
备忘录:
namespace DesignModeDemo.memento
{
class Memento
{
private string state; //--需要创建备忘录的数据
public Memento(string state)
{
this.State = state;
}
public string State
{
get
{
return state;
}
set
{
state = value;
}
}
}
}
管理者:
namespace DesignModeDemo.memento {
class Caretaker {
private Memento memento; //--也可以定义成一个list,保存多个时刻的备忘录
internal Memento Memento
{
get
{
return memento;
}
set
{
memento = value;
}
}
}
}
发起者:
namespace DesignModeDemo.memento
{
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);
}
}
}
客户端代码:
static void Main(string[] args)
{
Originator originator = new Originator();
originator.State = "before start";
Caretaker back = new Caretaker();
back.Memento = originator.createMemento();
originator.State = "starting";
originator.show();
//--从备忘录恢复
originator.setMemento(back.Memento);
originator.show();
Console.Read();
}
输出:
Story:
存放打游戏中的参数,只是多了些参数,其它与上面的代码完全一致。
组合模式
类型:结构型
使用场景:又叫部分-整体模式,将对象组合成树形结构以表示“部分-整体”的层次结构。
组合模式使得用户对单个对象与组合对象的使用具有一致性。
这个模式的要点是Composite类中,可能维护了很多子Component对象,可能一直递归下去。
转换成代码:
抽象Component类:
namespace DesignModeDemo.composite
{
abstract class Component
{
protected string name;
public Component(string name)
{
this.name = name;
}
public abstract void addComponent(Component comp);
public abstract void removeComponent(Component comp);
public abstract void displayComponent(int dept);
}
}
组合对象:
namespace DesignModeDemo.composite
{
class Composite : Component
{
private IList<Component> children = new List<Component>();
public Composite(string name) : base(name)
{
}
public override void addComponent(Component comp)
{
children.Add(comp);
}
public override void displayComponent(int dept)
{
Console.WriteLine(new String('-', dept) + name);
//--遍历显示下级
foreach(Component c in children)
{
c.displayComponent(dept+2);
}
}
public override void removeComponent(Component comp)
{
children.Remove(comp);
}
}
}
客户端代码:
static void Main(string[] args)
{
Composite root = new Composite("root");
root.addComponent(new Leaf("etc"));
root.addComponent(new Leaf("lib"));
Composite home = new Composite("home");
home.addComponent(new Leaf("idcim"));
home.addComponent(new Leaf("zxin10"));
Composite cmdb = new Composite("cmdb");
cmdb.addComponent(new Leaf("etc"));
cmdb.addComponent(new Leaf("log"));
home.addComponent(cmdb);
root.addComponent(home);
root.displayComponent(1);
Console.Read();
}
输出:
Story:
公司的管理系统,公司有很多平行的子部门,也可能有很多子公司,子公司具有相同的子部门。如:
结构图:
抽象公司类:
namespace DesignModeDemo.composite
{
abstract class Company
{
protected string name;
public Company(string name)
{
this.name = name;
}
public abstract void add(Company comp);
public abstract void remove(Company comp);
public abstract void display(int dept);
public abstract void doDuty();
}
}
具体子公司、子部门:
namespace DesignModeDemo.composite
{
class ChildCompany : Company
{
private IList<Company> childrenCompany=new List<Company>();
public ChildCompany(string name) : base(name)
{
}
public override void add(Company comp)
{
childrenCompany.Add(comp);
}
public override void display(int dept)
{
Console.WriteLine(new String('-', dept) + name);
//--遍历显示下级
foreach (Company c in childrenCompany)
{
c.display(dept + 2);
}
}
public override void doDuty()
{
foreach (Company c in childrenCompany)
{
c.doDuty();
}
}
public override void remove(Company comp)
{
childrenCompany.Remove(comp) ;
}
}
}
namespace DesignModeDemo.composite
{
class ChildCompany : Company
{
private IList<Company> childrenCompany=new List<Company>();
public ChildCompany(string name) : base(name)
{
}
public override void add(Company comp)
{
childrenCompany.Add(comp);
}
public override void display(int dept)
{
Console.WriteLine(new String('-', dept) + name);
//--遍历显示下级
foreach (Company c in childrenCompany)
{
c.display(dept + 2);
}
}
public override void doDuty()
{
foreach (Company c in childrenCompany)
{
c.doDuty();
}
}
public override void remove(Company comp)
{
childrenCompany.Remove(comp) ;
}
}
}
namespace DesignModeDemo.composite
{
class HRDepartment : Company
{
public HRDepartment(string name) : base(name)
{
}
public override void add(Company comp)
{
}
public override void display(int dept)
{
Console.WriteLine(new String('-', dept) + name);
}
public override void doDuty()
{
Console.WriteLine("{0},hr",name);
}
public override void remove(Company comp)
{
}
}
}
客户端:
static void Main(string[] args)
{
ChildCompany root = new ChildCompany("北京总公司");
root.add(new HRDepartment("总公司人力资源部"));
root.add(new FinDepartment("总公司财务部"));
ChildCompany home = new ChildCompany("华东公司");
home.add(new HRDepartment("华东公司人力资源部"));
home.add(new FinDepartment("华东公司财务部"));
ChildCompany nj = new ChildCompany("南京公司");
nj.add(new HRDepartment("南京公司人力资源部"));
nj.add(new FinDepartment("南京公司财务部"));
home.add(nj);
root.add(home);
root.display(1);
Console.Read();
}
输出:
桥接模式
类型:结构型
使用场景:将抽象部分与实现部分分离,使它们都可以独立的变化。这句话不太好理解,需要结合结构图:
这里可以看出来抽象与实现是分离的,抽象出了一个Operation方法,至于是选用A类的方法来实现还是B类的方法来实现,只要修改维护的聚合引用就行了。下面是一个更实际的结构图:
抽象层抽象出draw这个功能,画红色的圆还是画绿色的圆等,由具体的类来实现。现在是单维度在变化,如果从Shape里面继承出一个方形出来,并且增加画红色的方形和画绿色的方形,就成了多维度在变化,按需要组合即可。
将抽象部分与它的实现部分分离,可以理解为实现系统可能有多角度分类,每一种分类都有可能 变化,那么就把这种多角度分离现来让它们独立变化,减少它们之间的耦合。
转化成代码:
抽象Implementor类:
namespace DesignModeDemo.bridge {
abstract class Implementor {
public abstract void operation();
}
}
具体实现类:
namespace DesignModeDemo.bridge {
class CocreteImplementorA : Implementor {
public override void operation()
{
Console.WriteLine("CocreteImplementorA operation");
}
}
class CocreteImplementorB : Implementor {
public override void operation()
{
Console.WriteLine("CocreteImplementorB operation");
}
}
}
class Abstraction
{
protected Implementor implementor;
public void setImplementor(Implementor implementor)
{
this.implementor = implementor;
}
public virtual void operation()
{
implementor.operation();
}
}
namespace DesignModeDemo.bridge {
class RefinedAbstraction:Abstraction {
public override void operation()
{
implementor.operation();
}
}
}
客户端代码:
static void Main(string[] args)
{
Abstraction ab = new RefinedAbstraction();
ab.setImplementor(new CocreteImplementorA());
ab.operation();
ab.setImplementor(new CocreteImplementorB());
ab.operation();
Console.Read();
}
输出:
Story:
手机品牌和手机软件是两个不同的维度,手机品牌N上的软件不能运行在手机品牌M上,结构图应该使用组合,而不是继承。
有三种结构图:
前面两个结构图,当增加了手机品牌或增加了手机软件时,还要去修改原来的类,违返了开放—封闭原则。
抽象手机软件:
namespace DesignModeDemo.bridge {
abstract class HandsetSoft {
public abstract void run();
}
}
具体手机软件:
namespace DesignModeDemo.bridge {
class HandsetGame : HandsetSoft {
public override void run()
{
Console.WriteLine("运行手机游戏");
}
}
class HandsetMail : HandsetSoft {
public override void run()
{
Console.WriteLine("运行手机邮箱");
}
}
}
手机品牌:
namespace DesignModeDemo.bridge
{
abstract class HandsetBrand
{
protected HandsetSoft soft;
public void setHandsetSoft(HandsetSoft soft)
{
this.soft = soft;
}
public abstract void run();
}
class HandsetBrandM : HandsetBrand
{
public override void run()
{
Console.WriteLine("手机品牌M,运行:");
soft.run();
}
}
class HandsetBrandN : HandsetBrand
{
public override void run()
{
Console.WriteLine("手机品牌N,运行:");
soft.run();
}
}
}
客户端:
static void Main(string[] args)
{
HandsetBrand m = new HandsetBrandM();
m.setHandsetSoft(new HandsetMail());
m.run();
m.setHandsetSoft(new HandsetGame());
m.run();
m = new HandsetBrandN();
m.setHandsetSoft(new HandsetMail());
m.run();
m.setHandsetSoft(new HandsetGame());
m.run();
Console.Read();
}
输出:
命令模式
类型:行为型
使用场景:将一个请求封装成一个对象,从而可以用不同的请求对客户进行参数化。
命令模式的关键点是ConcreteCommand类中维护了一个Receiver的引用。
转换成代码:
抽象命令:
namespace DesignModeDemo.command
{
abstract class Command
{
protected Receiver receiver;
public Command(Receiver receiver)
{
this.receiver = receiver;
}
abstract public void execute();
}
}
具体命令:
namespace DesignModeDemo.command
{
class ConcerteCommand : Command
{
public ConcerteCommand(Receiver receiver) : base(receiver)
{
}
public override void execute()
{
receiver.action();
}
}
}
接收命令:
namespace DesignModeDemo.command {
class Receiver {
public void action()
{
Console.WriteLine("执行请求!");
}
}
}
执行命令类:
namespace DesignModeDemo.command
{
class Invoker
{
private Command command;
public void setCommand(Command command)
{
this.command = command;
}
public void executeCommand()
{
command.execute();
}
}
}
客户端:
static void Main(string[] args)
{
Command com = new ConcerteCommand(new Receiver());
Invoker invoke = new Invoker();
invoke.setCommand(com);
com.execute();
Console.Read();
}
Story:
烤烧烤功能就是常见的命令模式,顾客说怎么烤,摊主就怎么烤。
职责链模式
类型:行为型
使用场景:为请求创建了一个接收者对象的链,这种模式给予请求的类型,对请求的发送者和接收者进行解耦。典型的如JS中的事件冒泡。
这个模式的关键是有点像C语言中的链式结构,有一个指向下一个结构的指针。当然,这里是一个引用。
转换成代码:
namespace DesignModeDemo.responschain
{
abstract class Handler
{
protected Handler successor;//--下一个处理Handler
public void setSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void handleRequest(int request);
}
}
namespace DesignModeDemo.responschain
{
class ConcerateHandler1 : 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 ConcerateHandler2 : 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 ConcerateHandler3 : Handler
{
public override void handleRequest(int request)
{
if (request >= 20)
{
Console.WriteLine("{0} 处理请求 {1}", this.GetType().Name, request);
}
else if (successor != null)
{
successor.handleRequest(request); //--向下转移
}
}
}
}
客户端代码:
static void Main(string[] args)
{
ConcerateHandler1 h1 = new ConcerateHandler1();
ConcerateHandler2 h2 = new ConcerateHandler2();
ConcerateHandler3 h3 = new ConcerateHandler3();
h1.setSuccessor(h2);
h2.setSuccessor(h3);
int[] requests = { 4, 9, 15, 25 };
foreach (int i in requests)
{
h1.handleRequest(i);
}
输出:
一点思考:
职责链模式与状态模式有些相近,都有一个处理句柄,不过一个是处理请求,一个是处理上下文。另外,状态模式的状态是相互独立的,而职责链可理解为等级森严的一条链结构。
中介者模式
类型:行为型
使用场景:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互。
这里,Colleague(同事)与同事之间互不相识,但它们都认识中介者,中介者认识所有同事。
转换成代码:
抽象同事类:
namespace DesignModeDemo.mediator {
abstract class Colleague {
protected Mediator mediator; //--同事只认识中介者
public Colleague(Mediator mediator)
{
this.mediator = mediator;
}
}
}
具体同事为类:
namespace DesignModeDemo.mediator
{
class ConcreteColleague1 : Colleague
{
public ConcreteColleague1(Mediator mediator) : base(mediator)
{
}
public void send(string msg)
{
mediator.send(msg,this); //--通过中介者发送消息
}
public void notify(string msg)
{
Console.WriteLine("同事1得到消息:"+msg);
}
}
class ConcreteColleague2 : Colleague
{
public ConcreteColleague2(Mediator mediator) : base(mediator)
{
}
public void send(string msg)
{
mediator.send(msg, this); //--通过中介者发送消息
}
public void notify(string msg)
{
Console.WriteLine("同事2得到消息:" + msg);
}
}
}
抽象中介者:
namespace DesignModeDemo.mediator {
abstract class Mediator {
public abstract void send(string message,Colleague colleague); //--向某个同事发消息
}
}
具体中介者:
namespace DesignModeDemo.mediator
{
class ConcreteMediator : Mediator
{
private ConcreteColleague1 c1;
private ConcreteColleague2 c2;
internal ConcreteColleague1 C1
{
set
{
c1 = value;
}
}
internal ConcreteColleague2 C2
{
set
{
c2 = value;
}
}
public override void send(string message, Colleague colleague)
{
if(colleague==c1) //--如果消息由c1发出,则通知c2
{
c2.notify(message);
}else if(colleague == c2)
{
c1.notify(message);
}
}
}
}
Console.Read();
}
客户端代码:
static void Main(string[] args)
{
ConcreteMediator media = new ConcreteMediator();
ConcreteColleague1 c1 = new ConcreteColleague1(media);
ConcreteColleague2 c2 = new ConcreteColleague2(media);
media.C1 = c1;
media.C2 = c2;
c1.send("are you ok?");
c2.send("no ok");
Console.Read();
}
输出:
中介者优缺点:
中介者的优点是集中控制,使对象与对象之间解耦了;缺点也是来自于集中控制,使得中介者可能会比较复杂。
享元模式
类型:结构型
使用场景:享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。它主要用于减少创建对象的数量,以减少内存占用和提高性能。常结合HashMap使用。
这个结构图看起复杂,其实实际应用中不知不觉就用了。这里的重点不是享元类的方法,而是享元工厂创建享元的时机,以及如何获得享元对象。
转换成代码:
抽象享元:
namespace DesignModeDemo.flyweight {
abstract class Flyweight {
public abstract void operation(int state);
}
}
具体享元:
namespace DesignModeDemo.flyweight {
class ConcreateFlyweight : Flyweight {
public override void operation(int state)
{
Console.WriteLine("具体flyweight:"+state);
}
}
}
享元工厂:
namespace DesignModeDemo.flyweight
{
class FlyweightFactory
{
private Hashtable flys=new Hashtable();
public Flyweight getFlyweight(string key)
{
if(!flys.ContainsKey(key))
{
flys.Add(key,new ConcreateFlyweight());
}
return flys[key] as Flyweight;
}
}
}
客户端代码:
static void Main(string[] args)
{
int state = 20;
FlyweightFactory ff = new FlyweightFactory();
Flyweight fx = ff.getFlyweight("x");
fx.operation(--state);
Flyweight fy = ff.getFlyweight("y");
fy.operation(--state);
Console.Read();
}
输出:
Story:
享元模式有内部状态与外部状态之分。在享元对象内部并且不会随环境改变而改变的共享部分,称为内部状态;不可以共享部分则为外部状态。通常是把外部状态移到类实例的外面,在方法调用时将它们传递进来。
例如,对于给很多用户开发的网站,都是同一套东西,但用户的Id不同,结构图为:
抽象网站:
namespace DesignModeDemo.flyweight {
abstract class Website {
public abstract void user(User user); //--外部状态
}
}
具体网站:
namespace DesignModeDemo.flyweight
{
class ConcreateWebsite : Website
{
private string webName;
public ConcreateWebsite(string webName)
{
this.webName = webName;
}
public override void user(User user)
{
Console.WriteLine("网站分类:"+webName+",用户:"+user.Name);
}
}
}
外部状态,用户名:
namespace DesignModeDemo.flyweight
{
class User
{
private string name;
public User(string name)
{
this.name = name;
}
public string Name
{
get
{
return name;
}
}
}
}
网站工厂:
namespace DesignModeDemo.flyweight
{
class WebsiteFactory
{
private Hashtable website = new Hashtable();
public Website getWebsite(string key)
{
if (!website.ContainsKey(key))
{
website.Add(key, new ConcreateWebsite(key));
}
return website[key] as Website;
}
}
}
客户端代码:
static void Main(string[] args)
{
WebsiteFactory wf = new WebsiteFactory();
Website wx = wf.getWebsite("足球");
wx.user(new User("123"));
Website wy = wf.getWebsite("篮球");
wy.user(new User("456"));
Console.Read();
}
输出:
访问者模式
类型:行为型
使用场景:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
这个结构图的要点:
Element类的具体继承个数是定的,比如这里只有两个具体元素A和B。访问者接口定义了访问这两个具体元素的函数,参数是要访问的访问者。而元素类有一个接受访问者的函数。
转换成代码:
抽象元素,以及两个具体元素:
namespace DesignModeDemo.visitor {
abstract class Element {
public abstract void accept(Visitor visitor);
}
class ConcreateElementA:Element {
public override void accept(Visitor visitor)
{
visitor.visitorConcreateElementA(this);
}
}
class ConcreateElementB : Element {
public override void accept(Visitor visitor)
{
visitor.visitorConcreateElementB(this);
}
}
}
抽象访问者,及两个具体访问者:
namespace DesignModeDemo.visitor
{
abstract class Visitor
{
public abstract void visitorConcreateElementA(ConcreateElementA elementA);
public abstract void visitorConcreateElementB(ConcreateElementB elementB);
}
class ConcreateVisitor1 : Visitor
{
public override void visitorConcreateElementA(ConcreateElementA elementA)
{
Console.WriteLine("{0}被{1}访问",elementA.GetType().Name,this.GetType().Name);
}
public override void visitorConcreateElementB(ConcreateElementB elementB)
{
Console.WriteLine("{0}被{1}访问", elementB.GetType().Name, this.GetType().Name);
}
}
class ConcreateVisitor2:Visitor
{
public override void visitorConcreateElementA(ConcreateElementA elementA)
{
Console.WriteLine("{0}被{1}访问", elementA.GetType().Name, this.GetType().Name);
}
public override void visitorConcreateElementB(ConcreateElementB elementB)
{
Console.WriteLine("{0}被{1}访问", elementB.GetType().Name, this.GetType().Name);
}
}}
枚举所有元素对象:
namespace DesignModeDemo.visitor
{
class ObjectStructure
{
private IList<Element> elements = new List<Element>();
public void attach(Element e)
{
elements.Add(e);
}
public void detach(Element e)
{
elements.Remove(e);
}
public void accept(Visitor visitor)
{
foreach(Element e in elements)
{
e.accept(visitor);
}
}
}
}
客户端代码:
static void Main(string[] args)
{
ObjectStructure elementList = new ObjectStructure();
elementList.attach(new ConcreateElementA());
elementList.attach(new ConcreateElementB());
ConcreateVisitor1 visitor1 = new ConcreateVisitor1();
ConcreateVisitor2 visitor2 = new ConcreateVisitor2();
elementList.accept(visitor1);
elementList.accept(visitor2);
Console.Read();
}
输出:
Story:
用访问者模式实现这段话:
男人成功时,背后多半有一个伟大的女人。
女人成功时,背后大多有一个不成功的男人。
男人失败时,闷头喝酒,谁也不用劝。
女人失败时,眼泪汪汪,谁也劝不了。
男人恋爱时,凡事不懂也要装懂。
女人恋爱时,遇事懂也装作不懂。
这里面的男人、女人相当于两个固定数量的元素,成功、失败、恋爱这些状态相当于访问者,可以随时增加。
男人、女人及抽象类:
namespace DesignModeDemo.visitor {
abstract class Person {
public abstract void accept(Action visitor);
}
class Man : Person {
public override void accept(Action visitor)
{
visitor.getManConclustion(this);
}
}
class Womean : Person {
public override void accept(Action visitor)
{
visitor.getWomeanConclustion(this);
}
}
}
成功、失败、恋爱的状态:
namespace DesignModeDemo.visitor
{
abstract class Action
{
public abstract void getManConclustion(Man man); //--男人反应
public abstract void getWomeanConclustion(Womean womean); //--女人反应
}
class Fail:Action
{
public override void getManConclustion(Man man)
{
Console.WriteLine("{0} {1} 时,闷头喝酒,谁也不用劝", man.GetType().Name, this.GetType().Name);
}
public override void getWomeanConclustion(Womean womean)
{
Console.WriteLine("{0} {1} 时,眼泪汪汪,谁也劝不了", womean.GetType().Name, this.GetType().Name);
}
}
class Success : Action
{
public override void getManConclustion(Man man)
{
Console.WriteLine("{0} {1} 时,背后有一个成功的女人",man.GetType().Name,this.GetType().Name);
}
public override void getWomeanConclustion(Womean womean)
{
Console.WriteLine("{0} {1} 时,背后有一个不成功的男人", womean.GetType().Name, this.GetType().Name);
}
}}
class Amativeness:Action
{
public override void getManConclustion(Man man)
{
Console.WriteLine("{0} {1} 时,凡事不懂也要装懂", man.GetType().Name, this.GetType().Name);
}
public override void getWomeanConclustion(Womean womean)
{
Console.WriteLine("{0} {1} 时,遇事懂也装作不懂", womean.GetType().Name, this.GetType().Name);
}
}
枚举Person:
namespace DesignModeDemo.visitor
{
class PersonList
{
private IList<Person> persins = new List<Person>();
public void attach(Person p)
{
persins.Add(p);
}
public void detach(Person p)
{
persins.Remove(p);
}
public void accept(Action visitor)
{
foreach (Person p in persins)
{
p.accept(visitor);
}
}
}
}
客户端代码:
static void Main(string[] args)
{
PersonList persons = new PersonList();
persons.attach(new Man());
persons.attach(new Womean());
Success success = new Success();
Fail fail = new Fail();
Amativeness amativeness = new Amativeness();
persons.accept(success);
persons.accept(fail);
persons.accept(amativeness);
Console.Read();
}
输出:
附上软件开发的几个原则:
依赖倒置原则
抽象不应该依赖于细节,细节应该依赖于抽象,即要针对接口编程,而不是对实现编程。
里式代换原则
子类必须能够替换掉它们的父类型,一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里,把父类都替换成它的子类,程序的行为没有变化。
迪米特法则
也叫最少知识原则,如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。它的根本思想是强调了类之间的松耦合。类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。
合成/聚合复用原则
尽量使用合成/聚合,尽量不使用类继承。