1,适配器模式(Adapter):把已有的接口进行包装处理,转换成我们需要的接口。(注意:对象是已经存在的接口)
public abstract class Target {
public abstract void GetTemperature();}
class Adaptee {
public void 得到温度() {
Console.WriteLine("您得到了今日的温度"); }}public class Adapter:Target {
private Adaptee adaptee = new Adaptee();public override void GetTemperature() {
adaptee.得到温度(); }}注:java中可以用接口实现
2,外观模式(Facade):提供一个简洁一致的接口给客户端(把复杂的处理隐藏起来)。
通常隐藏起来的操作都是必须做的,重复的操作。或者是难明白的操作。
代码:
main(){
Movie movie = new Movie();
movie.playMovie();}
Class Movie(){
Light light = new Light();
Projector projector = new Projector();
light.closeLight();
projector.openProjecter();}
3,命令模式(Command):命令模式主要用来做以下几种工作
(1) Command模式是回调机制的一个面向对象的替代品。
所谓的回调函数指函数先在某处注册,而他将在稍后的某个需要的时候被调用。
如:为按钮注册一个Listener,然后自己写Listener接口的实现。等用户点击按钮后,
自己写的实现就会被调用。
(2) 在不同的时刻指定、排列和执行的请求。如:所有Command都装入一个List中
(3) 支持取消(UNDO)操作。
(4) 支持修改日志,这样当系统崩溃时这些修改可以被从新作一遍。
(5) 用构建在原语操作上的高层操作构造一个系统。这样一种结构支持事务的信息系统中很常见。
代码:
《敏捷软件开发:原则、模式与实践》与《Java与模式(清晰书签版)》书中的例子。
4,策略模式(Strategy):策略模式主要用来做以下几种工作
(1) 一个系统要动态地在几种算法中选择一种。那么算法可以包装到一个个具体的算法类里,
这些算法类都是一个抽象类的子类。
(2) 如果在一个系统中有许多类,他们之间的区别在于他们的行为,那么使用策略模式可以动态
地让一个对象在许多行为中选择一种行为。
(3) 如果一个对象有很多的行为,如果不用恰当的模式,这些行为只好使用多重条件选择语句来
实现。
代码:
class MainClass{
private StrategySuper strategy;
public void setStrategy(StrategySuper strategy){
this.strategy = strategy;
}
public void businessLogic{
// some implements
result = strategy.strategyMethod();
// some implements
}
}
abstract public class StrategySuper{
public abstract String strategyMethod();
}
public class StrategyOne extends StrategySuper{
public String strategyMethod(){
// concrete strategy one code
}
}
public class StrategyTwo extends StrategySuper{
public String strategyMethod(){
// concrete strategy two code
}
}
模板模式和策略模式的不同点在于 :模板模式使用继承来实现,策略模式使用组合来实现。代码:abstract public class TemplateClass{public void businessLogic(){// some business logic implements
result =calculateInterest();
// some business logic implements
}abstract public double calculateInterest();}
public class BankA extends TemplateClass{
public double calculateInterest(){
// concrete business logic
}
}
public class BankB extends TemplateClass{
public double calculateInterest(){
// concrete business logic
}
}
作用:用一个中介对象来封装一系列的对象之间的交互。中介者使各对象不需要显式地相 互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。public interface Mediator { }
public class ConcreteMediator implements Mediator {
//假设当前有两个成员.
private ConcreteColleague1 colleague1 = new ConcreteColleague1();
private ConcreteColleague2 colleague2 = new ConcreteColleague2();
...
}
public class Colleague {
private Mediator mediator;
public Mediator getMediator() {
return mediator;
}
public void setMediator( Mediator mediator ) {
this.mediator = mediator;
}
}
public class ConcreteColleague1 { }
public class ConcreteColleague2 { }
6,单例模式(Singleton):
代码:
public class Singleton {
private Singleton(){}
//在自己内部定义自己一个实例,是不是很奇怪?
//注意这是private 只供内部调用
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
7,MONOSTATE模式(Monostate):
public class MonoState {
private static String x;
public MonoState(){}
public String GetX() {
return x;
}
public void SetX(String x) {
MonoState.x = x;
}
}
MonoState的好处是:
1 对客户端程序来说是透明的。客户端程序可以随意创建对象,但是对象的状态是唯一的,这一点客户端不用知道。
2 可继承性。从MonoState派生出来的也是MonoState。实际上,所有的MonoState的派生类都是相同的MonoState的一部分,因为它们都共享相同的static变量。
3 支持多态性。因为MonoState的方法不像Singleton的static方法,它是可以被重写的。
4 易于创建和销毁。
缺点:
1 不能转换。非MonoState类不能通过继承转换为MonoState类。
2 效率。因为它会有对象,所以有许多产生,销毁的过程。这些通常都导致效率降低。
3 空间占用。因为MonoState的变量都是静态的,所以尽管MonoState不被使用,它们同样要占用空间。
4 平台约束。不能够在不同的JVM实体或者不同的平台上使用MonoState。
Singleton与Monostate的区别
1 Singleton模式强制结构上的单一性。它防止创建多个对象实例。
相反,Monostate强制行为上的单一性,没有加强结构方面的限制。
2 如果希望派生来来约束一个现存类,并且不介意它的调用者都必须要调用instance()方法来获
取访问权,那么使用Singleton;如果希望类的单一本质对使用者透明,希望使用单一对象的
多态派生对象,用Monostate。
设计模式的一些原则:
1,单一职责原则(SRP):一个类承担的职责过多,就等于把这些职责耦合在一起了,
一个职责的变化可能会消弱或抑制这个类完成其它职责的能力。
例子:
interface Moden{
public void dial(String pno);
public void hangup();
public void send(char c);
public void recv();
}
这个接口有两个职责:1,连接管理。2,数据通信。
这两个职责应该被分开吗?这依赖于程序的变化。如果程序变化影响到连接函数的签名,那么这个设计就具有臭味。
因为send和recv类必须重新编译,部属的次数超过我们希望的次数。这种情况下职责就应该被分离。
即:把dial和hangup定义到一个接口中,send和recv定义到一个接口中。
别一方面,如果应用程序的变化总导致这两个职责同时变化,那么就不必分离他们。
如果分离了他们,就会发生不必要的复杂性。
如果没有征兆就去应用SRP,或者其它原则都是不明智的。
2,开放-封闭原则(OCP)
概念:
1)对于扩展是开放的
这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有那些改变的新行为。
换句话说,我们可以改变模块的的功能。
2)对于更改是封闭的
对于模块行为进行改变时,不必改动模块的源代码或者二进制代码。
总结上面的原则,其实现就是
1)定义接口,主程序调用接口,具体实现类实现接口。
2)实现类的初始化方式使用反射,或者Spring等框架的DI功能。
接口:
interface ICommunication(){
public String sendMessage(String message);
}
主类:
class MainClass{
String message = "Hello World";
ICommunication ic;// 这里通过DI功能注入TCPSender,但没写setter方法。
public String MainClassSendMessage(){
return ic.sendMessage(message);
}
实现接口的子类
class TCPSender implements ICommunication{
public String sendMessage(String message){
// 具体的实现
}
}
总结了一下,和GRASP原则的“间接性”和“防止变异”原则一样。
3,里氏代换原则(LSP):
简单的说就是“基类出现的地方,子类也可一定可以出现”。
实现方法就是:为子类定义接口,子类必须按照所定义的接口实现功能。
代码和上面的开放封闭原则根本一样,主要思想就是子类不要创建新的方法让调用它的类使用,
因为这样:1)得修调用它的类 2)在调用它的类中必须分清当前的子类是哪个子类,这样就
失去了多态的意义。
4,接口隔离原则(ISP)不能强迫用户去依赖那些他们不使用的接口。换句话说,使用多个专门的接口比使用单一的总接口总要好。
例子:假如有一个Door,有lock,unlock功能,另外,可以在Door上安装一个Alarm而使其具有报警功能。用户可以选择一般的Door,也可以选择具有报警功能的Door。方法一:
在Door接口里定义所有的方法。
但这样一来,依赖Door接口的CommonDoor却不得不实现未使用的alarm()方法。违反了ISP原则。
在Alarm接口定义alarm方法,在Door接口定义lock,unlock方法。接口之间无继承关系。CommonDoor实现Door接口。
1),同时实现Door和Alarm接口。
2),继承CommonDoor,并实现Alarm接口。该方案是继承方式的Adapter设计模式的实现。注意:接口的设计粒度越小,系统越灵活,这是不争的事实。但是,灵活的同时也带来了结构的复杂化,开发难度增加,可维护性降低,这不是一个项目或产品所期望看到的,所以接口设计一定要注意适度,这个度只能根据经验和常识判断,没有一个固化或可测量的标准。
在在在