`
lisa.zhou
  • 浏览: 3750 次
  • 性别: Icon_minigender_2
最近访客 更多访客>>
社区版块
存档分类
最新评论

Java设计模式学习笔记上

 
阅读更多



 一:设计原则

  • 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化得代码混在一起。
  • 针对接口编程,而非针对实现编程。
  • 多用组合,少用继承。 'has a' is better than 'is a'
  • 为交互对象之间的松耦合设计而努力
  • 开放关闭原则:类应该对扩展开放,对修改关闭(在不修改代码的情况下,对功能进行扩展)
  • 要依赖抽象,不要依赖具体类

二:策略模式(strategy)

   定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

  示例图:

 

 FlyBehavior 和 QuackBehavior分别是算法族对象的接口; 客户中直接声明接口,使算法独立,不影响客户,同时使算法方法得到重用;

 

另一示例:comparator 和comparable 

任何实现comparable接口的对象都能通过sort方法排序,同时可以通过策略模式选择每个对象的比较策略,可以为每个对象实现各自的Comparator方法。

 

三:观察者模式(observer)

  • 定义:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会受到通知,并自动更新。
  • 出版者+订阅者=观察者模式     出版者1——*订阅者
  • java内置观察者模式:

 

       观察者类 observable.class;
      观察者接口Observer;

      实现中subject类型的类需继承自observable.class;

      observer类型的对象需实现observer接口,实现update()

 

四:装饰者模式(Decorator)

  • 用途:在不修改任何底层代码的情况下,给你的(或别人的)对象赋予新的职责。
  • 特有原则:开放-关闭原则。但在应用中让OO每个地方都采用开放-关闭原则是一种浪费,一般在设计中找到最有可能改变的地方,然后应用开放-关闭原则。
  • 定义:装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
  • 特性:装饰者和被装饰者有相同的超类。 可以用一个或多个装饰者逐层装饰一个对象。装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
  • Whip,Mocha,DarkRoast拥有同样的超类,whip和mocha对DarkRoast进行层层装饰

     

五:工厂模式(Factory)

  • 设计原则:要依赖抽象,不要依赖具体类。又称依赖倒置原则
  • 工厂方法模式:定义了创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
  • 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定类型
  • 工厂方法模式与抽象工厂对比

     上例是简单工厂方法,在SimplePizzaFactory产生具体的Pizza产品。

     上例是工厂模式,不同的PizzaStore根据自己店的风格生产出不同的Pizza。

     上例是抽象工厂模式,每个工厂负责生产一个产品家族(我们可以设想成Pizza的产品原料)
      最后唠叨:工厂方法模式,只不过就是通过子类来创建对象。客户只需知道抽象类型,由子类负责决定具体类型。
      抽象工厂负责创建一个产品家族,这个类型的子类定义了产品被产生的方法。要想使用这个工厂,必须先示例化它,然后将它传入到一些针对抽象类型所写的代码中。缺陷:当加入新产品时,需要改变接口及接口相应的子类。

 

六:单例模式(Singletone)

  • 定义:确保一个类只有一个实例,并提供全局访问点。
  • 实现:在java实现中需要私有的构造函数、一个静态方法和一个静态变量     
    public class Singleton {
    	private static Singleton uniqueInstance;
    	private Singleton(){
    		
    	}
    	
    	public static Singleton getInstance(){
    		if(uniqueInstance == null){
    			uniqueInstance = new Singleton();
    		}
    		return uniqueInstance;
    	}
    }
     
  • 用途:线程池,缓存,对话框,处理偏好设置和注册表的对象,日志对象,充当打印机、显卡等设备的驱动程序的对象
  • 好处:确保一个对象只有一个实例;在需要时才创建对象(这一点解决了全局静态变量的缺点)
  • 缺陷:当有多线程出现时,若同时第一次调用getInstance方法,很有可能会产生两个不同的Singleton对象,这就违反了单例原则,但若直接对getInstance对象加上synchronized则会大大降低程序的性能
  • 寻求合适渠道:确保单例模式能在多线程的情况下正常工作
  1. 若getInstance()的性能对应用程序不是很关键,那就用synchronized做处理吧,不做其他操作。但若getInstance()频繁运行,就需要重新考虑了
  2. 若应用程序急切需要使用单例实例,并在创建和运行时的负担不繁重,则在声明静态变量时直接创建
  3. 如果很关系性能,那么用”双重检查锁“,在getInstance()中减少使用同步
    public class Singleton {
    	private volatile static Singleton uniqueInstance;
    	private Singleton(){}
    	
    	public static Singleton getInstance(){
    		if(uniqueInstance == null){
    			synchronized (Singleton.class) {
    				uniqueInstance = new Singleton();
    			}
    		}
    		return uniqueInstance;
    	}
    } 
     只有在第一次调用getInstance()时使用同步;但不适用于 1.4及更早版本的java中

七:命令模式(Command)

  • 定义:将请求封装成对象,这可以让你使用不同的请求、队列,或者日志请求来参数化其他对象。命令模式也支持撤销操作
  • 实现:将发出请求的对象和执行请求的对象进行解耦;两者之间通过命令对象进行沟通

  •  具体例子:设计一个遥控器API,有一个开关槽,负责管理各个电器的开关

  定义Light等命令执行者,这里以Light为例
public  class Light {
	private String name;
	public Light(String name) {
		super();
		this.name = name;
	}
	public  void on(){
		System.out.println("light " + name +" is off");
	}
	public  void off(){
		System.out.println("light " + name +" is on");
	}
}
   定义一系列命令对象,包装执行请求的对象,并定义execute()供RemoteControl进行调用,将RemoteControl和Light进行解耦。
public class LightOnCommand implements Command {
	Light light;
	public LightOnCommand(Light light){
		this.light = light;
	}
	
	@Override
	public void execute() {
		light.on();
	}
}
public class LightOffCommand implements Command {
	Light light;
	public LightOffCommand(Light light){
		this.light = light;
	}
	
	@Override
	public void execute() {
		light.off();
	}
}
 定义RemoteControl 用来管理一系列的命令对象。这里有一组是开命令对象,一组是关命令对象。
public class RemoteControl {
	Command[] onCommands;
	Command[] offCommands;
	 
	/*
	 * init the remote control : all have no command
	 */
	public RemoteControl(){
		Command noCommand = new NoCommand();
		onCommands = new Command[5];
		offCommands = new Command[5];
		for(int i=0 ;i<onCommands.length ;i++){
			onCommands[i] = noCommand;
			offCommands[i] = noCommand;
		}
	}
	
	public void setCommand(int slot,Command onCommand,Command offCommand){
		onCommands[slot] = onCommand;
		offCommands[slot] = offCommand;
	}
	
	public void onButtonWasPressed(int slot){
		onCommands[slot].execute();
	}
	public void offButtonWasPressed(int slot){
		offCommands[slot].execute();
	}
	
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("\n-------Remote Control--------------\n");
		for(int i = 0;i <onCommands.length;i++){
			sb.append("[slot"+i+"]"+ onCommands[i].getClass().getName()+"  "+offCommands[i].getClass().getName()+"\n");
		}
		return sb.toString();
		
	}
}
   定义 RemoteControlLoader 来装载各个命令对象,并封装一系列的命令请求,按下按钮进行测试
public class RemoteControlLoader {
	public static void main(String[] args){
		RemoteControl remoteControl = new RemoteControl();
		
		Light livingRoomLight = new Light("Living Room");
		Light outdoorLight = new Light("OutDoor");
		GarageDoor gd = new GarageDoor();
		Stereo stereo = new Stereo();
		
		//commands
		Command livingRoomLightOnCommand = new LightOnCommand(livingRoomLight);
		Command livingRoomLightOffCommand = new LightOffCommand(livingRoomLight);
		Command outdoorLightOnCommand = new LightOnCommand(outdoorLight);
		Command outdoorlightOffCommand = new LightOffCommand(outdoorLight);
		Command gdOpenCommand = new GarageDoorOpenCommand(gd);
		Command gdCloseCommand = new GarageDoorCloseCommand(gd);
		Command stereoOnCommand = new StereoOnWithCDCommand(stereo);
		Command stereoOffCommand = new StereoOffWithCDCommand(stereo);
		
		//load the button info to remote control
		remoteControl.setCommand(0, livingRoomLightOnCommand, livingRoomLightOffCommand);
		remoteControl.setCommand(1, outdoorLightOnCommand, outdoorlightOffCommand);
		remoteControl.setCommand(2, gdOpenCommand, gdCloseCommand);
		remoteControl.setCommand(3, stereoOnCommand, stereoOffCommand);
		
		System.out.println(remoteControl);//show the remote control settings
		
		//press the button to invoke the relative commands
		remoteControl.onButtonWasPressed(0);
		remoteControl.offButtonWasPressed(0);
		remoteControl.onButtonWasPressed(1);
		remoteControl.offButtonWasPressed(1);
		remoteControl.onButtonWasPressed(2);
		remoteControl.offButtonWasPressed(2);
		remoteControl.onButtonWasPressed(3);
		remoteControl.offButtonWasPressed(3);
	}
}
  • 其他的: 若想要对一下子执行多个命令,可以创建宏命令对象
    public class MacroCommand implements Command {
    	Command[] commands;
    	public MacroCommand(Command[] commands) {
    		this.commands = commands;
    	}
    
    	@Override
    	public void execute() {
    		if(commands != null){
    			for(Command command : commands){
    				command.execute();
    			}
    		}
    	}
    }
     在测试类中,可以创建一系列的命令对象放入宏命令对象中。
  • 常见用途:日程安排,线程池,工作队列中的队列请求(工作队列类和进行计算的对象完全解耦);日志请求(将用户的操作作记录进行日志存储,一旦系统死机,这些操作记录对象将会被重新加载并以正确的次序执行)

八:适配器模式(Adapter)和外观模式(facade)

  • 定义-适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。
  • 适配器模式又可分为对象适配器和类适配器

     在类适配器中,需要多重继承,在java中不可能。在对象适配器中利用组合的方式将请求传送给被适配者(在Adapter中声明Adaptee实例,并调用Adaptee的方法)
  • 定义-外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

     
  • 两者意图不同:适配器模式意在改变接口类型以符合客户的需求。而外观模式是提供子系统的一个简化接口,方便用户操作(类似于在一个新的接口中将子系统的一系列方法封装成另一个方法供用户使用,用户无需考虑中间都调用了哪些类;当然这些子系统的接口仍然存在供用户随时调用)
  • 大小: 379.9 KB
  • 大小: 27.6 KB
  • 大小: 55 KB
  • 大小: 157.7 KB
  • 大小: 46.7 KB
  • 大小: 27.6 KB
  • 大小: 72.1 KB
  • 大小: 87.8 KB
  • 大小: 203.8 KB
  • 大小: 278 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics