1. 意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点
2. 动机
对于一些类来说,只有一个实例是非常重要的。虽然系统中可以有许多打印机,但却只应该有一个打印假脱机,只应该有一个文件系统和一个窗口管理器。一个会计系统只能应用于一个公司
怎样才能保证一个类只有一个实例,并且这个实例易于被访问呢?一个全局变量使得一个对象可以被访问,但它不能防止你实例化多个对象。一个更好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其它实例可以被创建(通过截取创建新对象的请求),并且提供一个访问该实例的方法。这就是singleton模式。
3. 适用性
在下面的情况下载可以使用singelton模式。当类只有一个实例,并且客户可以从一个众所周知的访问点访问它时。当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
4. 示例
class ExampleSingleton
{
/**************************************************************************************/
//单例/单体模式
/**************************************************************************************/
ExampleSingleton()
{ }
public void PrintHello()
{
//MessageBox.Show("Hello World!");
System.Console.WriteLine("Hello World!");
}
static ExampleSingleton singleton = new ExampleSingleton();
public static ExampleSingleton Singleton
{
get { return singleton; }
}
}
注意:singleton对象只有私有构造函数,这样,就不能在singleton类之外的singleton类创建对象,从而确保只有一个这样的对象。
1. 背景
1) 为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。这里很容易出现的一个问题n多的子类继承自抽象基类,我们不得不在每次要用到子类的地方就编写诸如new ×××;的代码。这里带来两个问题:
A. 客户程序员必须知道实际子类的名称(当系统复杂后,命名将是一个很不好处理的问题,为了处理可能的名字冲突,有的命名可能并不是具有很好的可读性和可记忆性,就姑且不论不同程序员千奇百怪的个人偏好了。
B. 程序的扩展性和维护变得越来越困难。
2) 还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。这里的意思为:假设我们在类A中要使用到类B,B是一个抽象父类,在A中并不知道具体要实例化那一个B的子类,但是在类A的子类D中是可以知道的。在A中我们没有办法直接使用类似于new ×××的语句,因为根本就不知道×××是什么。
3) 以上两个问题也就引出了Factory模式的两个最重要的功能:
A. 定义创建对象的接口,封装了对象的创建;
B. 使得具体化类的工作延迟到了子类中。
2. 适用性
一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
这个系统有多于一个的产品族,而系统只消费其中某一产品族。
同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
3. 类图
4. 示例
/********************************************************************************************/
//工厂模式
//Herbivoer--食草动物
//Canivoer--食肉性动物
//Bison--美洲野牛
/********************************************************************************************/
//抽象工厂(Abstract Factory)
abstract class ContinentFactory
{
//Methods
public abstract Herbivoer CreateHerbivoer();
public abstract Canivoer CreateCanivoer();
}
//ContinentFactory1
class AfricaFactory : ContinentFactory
{
public override Herbivoer CreateHerbivoer()
{
return new WildeBeest();
}
public override Canivoer CreateCanivoer()
{
return new Lion();
}
}
//ContinentFactory2
class AmericaFactroy : ContinentFactory
{
public override Herbivoer CreateHerbivoer()
{
return new Bison();
}
public override Canivoer CreateCanivoer()
{
return new Wolf();
}
}
//抽象产品(Abstract Product)
abstract class Herbivoer
{ }
abstract class Canivoer
{
public abstract void Eat(Herbivoer h);
}
//productA1
class WildeBeest : Herbivoer
{
public override string ToString()
{
return "WildeBeest";
}
}
//productB1
class Lion : Canivoer
{
//Method
public override void Eat(Herbivoer h)
{
Console.WriteLine(this + " eat " + h);
}
public override string ToString()
{
return "Lion";
}
}
//productA2
class Bison : Herbivoer
{
public override string ToString()
{
return "Bison";
}
}
//productB2
class Wolf : Canivoer
{
//Method
public override void Eat(Herbivoer h)
{
Console.WriteLine(this + " eat " + h);
}
public override string ToString()
{
return "Wolf";
}
}
//客户端(Client)
class AnimalWorld
{
private Herbivoer herbivoer;
private Canivoer canivoer;
public AnimalWorld(ContinentFactory factory)
{
herbivoer = factory.CreateHerbivoer();
canivoer = factory.CreateCanivoer();
}
public void RunFoodChain()
{
canivoer.Eat(herbivoer);
}
}
class GameApp
{
public static void Main(string[] args)
{
// Create and run the Africa animal world
//ContinentFactory africa = new AfricaFactory();
AfricaFactory africa = new AfricaFactory();
AnimalWorld world = new AnimalWorld(africa);
world.RunFoodChain();
// Create and run the America animal world
//ContinentFactory america = new AfricaFactory();
AmericaFactroy america = new AmericaFactroy();
world = new AnimalWorld(america);
world.RunFoodChain();
Console.ReadKey();
}
}
1. 意图
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
2. 动机
有时候我们希望给某个对象而不是整个类添加一些功能
例如:一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性,比如边框、行为。
使用继承机制是添加功能的一种有效途径,从其他类继承过来的边框特性可以被多个子类的实例所使用,但这种方法不够灵活,因为边框的选择是静态的,用户不能控制组件加边框的方式和时机。
一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加边框。我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用它的用户是透明的。它将用户请求转发给该组件,并且可能在转发前后执行一些额外的动作(例如画一个边框)。
透明性使得你可以递归的嵌入多个装饰,从而可以添加任意多的功能。
visualComponent是一个描述可视对象的抽象类,它定义了绘制和事件处理的接口。
Decorator中存在一个Component的对象,来接收所要装饰的组件—被装饰
继承方式
组合方式
3. 适用性
1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
2. 处理那些可以撤销的职责
3. 当不能采用生成子类的方法进行扩充时。A可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使子类数目呈爆炸性增长。B可能是因为类定义被隐藏,或类定义不能用于生成子类。
4. 结构
Component ( VisualComponent )
定义一个对象接口,可以给这些对象动态地添加职责。
ConcreteComponent ( TextView )
定义一个对象,可以给这个对象添加一些职责。
Decorator
维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
ConcreteDecorator(BoaderDecorator,ScrollDecorator)
向组件添加职责。
Decorator
将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。
5. 效果分析
(1) 比静态继承更灵活
可以用添加和分离的方法,用装饰在运行时增加和删除职责。而继承机制要求为每个添加的职责创建一个新的子类。更灵活的添加装饰:
使用Decorator模式可以很容易地重复添加一个特性,例如在TextView上添加双边框时,仅需添加两个BoarderDecorator即可。而两次继承Boarder类则极容易出错。
(2) 避免在层次结构高层的类有太多的特征
Decorator模式提供了一种“即用即付”的方法来添加职责。可以通过定制来逐步的构造复杂的对象。
6. 实例分析
Decorator装饰或者Wrapper包装这个些词太容易让人想到的是图形用户界面,这些方面的应用了。但这仅仅是一种形象的表达而已,不局限于此。
///
/// 武器
///
abstract class Weapon
{
private double ammo;//弹药
public double Ammo
{
get { return ammo; }
set { ammo = value; }
}
private double attack;//攻击
public double Attack
{
get { return attack; }
set { attack = value; }
}
private double speed;//速度
public double Speed
{
get { return speed; }
set { speed = value; }
}
private string name;//名字
public string Name
{
get { return name; }
set { name = value; }
}
public abstract void ShowInfo();
}
///
/// 步枪
///
class Rifle : Weapon
{
public Rifle()
{
this.Ammo = 100;
this.Attack = 10;
this.Speed = 5;
this.Name = "Rifle";
}
public override void ShowInfo()
{
Console.WriteLine(string.Format("ammo\t{0}", Ammo));
Console.WriteLine(string.Format("attack\t{0}", Attack));
Console.WriteLine(string.Format("speed\t{0}", Speed));
Console.WriteLine(string.Format("name\t{0}", Name));
}
}
abstract class Decorator : Weapon
{
protected Weapon w;
public Decorator(Weapon w)
{
this.w = w;
}
public override void ShowInfo()
{
w.ShowInfo();
}
}
///
/// 强化
///
class Enhance : Decorator
{
public Enhance(Weapon w) : base(w) { }
public void EnhanceAmmo()
{
w.Ammo += 20;
Console.WriteLine(">>>>>>>>>>>>Enhanced");
}
}
///
/// 装备
///
class Wear : Decorator
{
public Wear(Weapon w) : base(w) { }
public void WearByRate(double rate)
{
w.Speed = w.Speed * rate;
w.Attack = w.Attack * rate;
Console.WriteLine(">>>>>>>>>>>>Worn");
}
}
class Program
{
static void Main(string[] args)
{
Weapon w = new Rifle();
w.ShowInfo();
Enhance enhancedWeapon = new Enhance(w);
enhancedWeapon.EnhanceAmmo();
enhancedWeapon.ShowInfo();
Wear wornWeapon = new Wear(w);
wornWeapon.WearByRate(0.8);
wornWeapon.ShowInfo();
Console.ReadKey();
}
}
代码说明
Weapon是抽象构件角色。
Rifle是具体构件角色,实现抽象构件的接口。
Decorator是装饰角色。装饰角色有两个特点,一是继承了抽象构件的接口,二是有一个构件角色的实例。
Enhance和Wear是具体装饰角色,它们负责给构件附加责任。
客户端在使用装饰角色的时候并没有针对抽象构件进行编程,因为我们确实需要使用具体装饰角色提供的额外方法,这种类型的装饰叫做半透明装饰。