月度归档:2017年02月

设计模式之适配器模式

适配器模式有点像是现实世界中的各种"转接头"的概念.比如鼠标的转接头有 ps2转usb之类的.OO适配器和真是世界的适配器扮演者同样的角色:将一个接口转换成另一个接口,以符合客户的期望.

定义:适配器模式将一个类的接口,转换成客户期望的另一个接口.适配器让原本接口不兼容的类可以合作无间.

对象适配器

适配器实现目标接口,被适配者的对象会通过参数传入适配器,也就是适配器类依赖被适配者.
这个适配器模式充满着良好的OO设计原则:使用对象组合,以修改的接口包装被适配者:这种做法还有额外的优点,那就是,被适配者的任何子类,都可以搭配着适配器使用.

类适配器

类适配器需要多重继承才能够实现它,这在Java中是不可能的.

下面张贴一个对象适配器的例子:

public interface Duck {
	public void quack();
	public void fly();
}
public class MallardDuck implements Duck {
	public void quack() {
		System.out.println("Quack");
	}
 
	public void fly() {
		System.out.println("I'm flying");
	}
}
import java.util.Random;

public class DuckAdapter implements Turkey {
	Duck duck;
	Random rand;
 
	public DuckAdapter(Duck duck) {
		this.duck = duck;
		rand = new Random();
	}
    
	public void gobble() {
		duck.quack();
	}
  
	public void fly() {
		if (rand.nextInt(5)  == 0) {
		     duck.fly();
		}
	}
}
public interface Turkey {
	public void gobble();
	public void fly();
}
public class TurkeyTestDrive {
	public static void main(String[] args) {
		MallardDuck duck = new MallardDuck();
		Turkey duckAdapter = new DuckAdapter(duck);
 
		for(int i=0;i<10;i++) {
			System.out.println("The DuckAdapter says...");
			duckAdapter.gobble();
			duckAdapter.fly();
		}
	}
}

可以看到适配器构造函数需要传入被适配者的对象,然后适配器根据实现的接口来调用相应的被适配者的各种方法.

JDK环境变量相关

Ubuntu下安装oracle版本的JDK的话,可以通过添加ppa,然后 apt-get install,非常方便,而且之后环境变量基本上已经配置好了。环境变量的配置在 /etc/profile.d/下有两个文件:jdk.csh和jdk.sh,里面配置了环境变量。

我们可以在终端中输入命令 $echo $PATH 来查看环境变量,看看是否有jre jdk之类的环境变量在里面。

由于Ubuntu下面往往可以安装多个版本的 jdk,比如openJdk(开源的版本),所以我们需要工具来设置默认的java。

相关命令:

update-alternatives --config java 可以配置默认的java版本,也就是jre版本
update-alternatives --config javac 这个当然就是用来配置默认的jdk版本了,以下只举例 java
update-alternatives --display java 显示当前链接目前指向,其实就是在终端输入java命令,其实是指向 /usr/bin/java,而 /usr/bin/java又指向了哪里呢?这个命令就会显示出来了。
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.8.0_25 /bin/java 300 这个之后 update-alternatives --display java就会多出来一行了

一个显示轮班的js小工具

源代码:https://coding.net/u/baozhuwanglei/p/xiaoxiangmu/git/tree/master/lunban

视频演示

没有任何服务器端的代码,就是js+html,所以反应速度很快.效果如下图:

没有使用 jQuery,因为觉得没有必要,毕竟只是个小东西.
兼容性有问题,IE8不能显示,其他版本的IE浏览器可能也有同样的问题.IE浏览器对 innerHTML的支持有问题.后来我使用 jQuery的 append,可还是出现同样的问题,IE8不能显示,而火狐和chrome浏览器都正常.

算法:
三班两倒,也就是上班12小时,休息24小时.
算法很简单,首先随便选取某天的上班开始时间作为一个参照点,以时间戳的形式,三班都有.

比如有 甲 乙 丙 三班
甲乙丙的参照点时间戳分别为 A B C
求 D时为甲乙丙哪一班上班?

算法为:分别判断
(D - A)%(36*60*60) < 12*60*60 成立为甲上班
(D - B)%(36*60*60) < 12*60*60 成立为乙上班
(D - C)%(36*60*60) < 12*60*60 成立为丙上班


算法的思路是:一个循环是36小时,所以如果D-A除以36小时余数小于12小时的话,那么D的时间就是甲的上班时间。A是甲上班的任何一个打卡时间。

具体算法的实现:

//根据日期计算
	function pb(date) {
		date = new Date(Date.parse(date.replace(/-/g, "/")));
		date = date.getTime();	//为毫秒
		date = date/1000;	//转换为秒
		
		//alert(date);
		//alert(Math.abs(date-sy)%129600);
		
		if (date-sy==0 || Math.abs(date-sy)%129600<43200) {
			return '宋彦洲 杨延军';
		} else if (date-zw==0 || Math.abs(date-zw)%129600<43200) {
			return '朱建英 王瑶苛';
		} else if (date-ww==0 || Math.abs(date-ww)%129600<43200) {
			return '王磊 王啸';
		}
	}

应一位同事的建议,添加了一个小功能,计算工时。

设计模式之命令模式

命令模式就是将请求封装为一个对象,从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作。

在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。

这是一个遥控器的例子
一个灯类,有开灯、关灯、昏暗灯光之类的方法。
一个接口命令类:定义了执行和撤销两个方法。
下面有四个类实现了命令接口,分别是:开灯命令、关灯命令、昏暗开灯命令、昏暗关灯命令。
一个遥控器类,在模式中叫做调度者,依赖命令接口,调用命令的方法。
客户类,上图没有画,初始化命令类,传入遥控器类,调用遥控器类相应方法。

代码:
Light.java:

package headfirst.command.undo;

public class Light {
	String location;
	int level;

	public Light(String location) {
		this.location = location;
	}

	public void on() {
		level = 100;
		System.out.println("Light is on");
	}

	public void off() {
		level = 0;
		System.out.println("Light is off");
	}

	public void dim(int level) {
		this.level = level;
		if (level == 0) {
			off();
		}
		else {
			System.out.println("Light is dimmed to " + level + "%");
		}
	}

	public int getLevel() {
		return level;
	}
}

命令接口 Command.java:

package headfirst.command.undo;

public interface Command {
	public void execute();
	public void undo();
}

开灯命令 LightOnCommand.java:

package headfirst.command.undo;

public class LightOnCommand implements Command {
	Light light;
 
	public LightOnCommand(Light light) {
		this.light = light;
	}
 
	public void execute() {
		light.on();
	}
 
	public void undo() {
		light.off();
	}
}

关灯命令 LightOffCommand.java:

package headfirst.command.undo;

public class LightOffCommand implements Command {
	Light light;
 
	public LightOffCommand(Light light) {
		this.light = light;
	}
 
	public void execute() {
		light.off();
	}
 
	public void undo() {
		light.on();
	}
}

昏暗开灯命令 DimmerLightOnCommand.java:

package headfirst.command.undo;

public class DimmerLightOnCommand implements Command {
	Light light;
	int prevLevel;

	public DimmerLightOnCommand(Light light) {
		this.light = light;
	}

	public void execute() {
		prevLevel = light.getLevel();
		light.dim(75);
	}

	public void undo() {
		light.dim(prevLevel);
	}
}

昏暗关灯 DimmerLightOffCommand.java:

package headfirst.command.undo;

public class DimmerLightOffCommand implements Command {
	Light light;
	int prevLevel;

	public DimmerLightOffCommand(Light light) {
		this.light = light;
		prevLevel = 100;
	}

	public void execute() {
		prevLevel = light.getLevel();
		light.off();
	}

	public void undo() {
		light.dim(prevLevel);
	}
}

空命令 NoCommand.java:

package headfirst.command.undo;

public class NoCommand implements Command {
	public void execute() { }
	public void undo() { }
}

遥控器 RemoteControlWithUndo.java:

package headfirst.command.undo;

import java.util.*;

//
// This is the invoker
//
public class RemoteControlWithUndo {
	Command[] onCommands;
	Command[] offCommands;
	Command undoCommand;
 
	public RemoteControlWithUndo() {
		onCommands = new Command[7];
		offCommands = new Command[7];
 
		Command noCommand = new NoCommand();
		for(int i=0;i<7;i++) {
			onCommands[i] = noCommand;
			offCommands[i] = noCommand;
		}
		undoCommand = noCommand;
	}
  
	public void setCommand(int slot, Command onCommand, Command offCommand) {
		onCommands[slot] = onCommand;
		offCommands[slot] = offCommand;
	}
 
	public void onButtonWasPushed(int slot) {
		onCommands[slot].execute();
		undoCommand = onCommands[slot];
	}
 
	public void offButtonWasPushed(int slot) {
		offCommands[slot].execute();
		undoCommand = offCommands[slot];
	}
 
	public void undoButtonWasPushed() {
		undoCommand.undo();
	}
  
	public String toString() {
		StringBuffer stringBuff = new StringBuffer();
		stringBuff.append("\n------ Remote Control -------\n");
		for (int i = 0; i < onCommands.length; i++) {
			stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName()
				+ "    " + offCommands[i].getClass().getName() + "\n");
		}
		stringBuff.append("[undo] " + undoCommand.getClass().getName() + "\n");
		return stringBuff.toString();
	}
}

入口类:

package headfirst.command.undo;

public class RemoteLoader {
 
	public static void main(String[] args) {
		RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();
 
		Light livingRoomLight = new Light("Living Room");
 
		LightOnCommand livingRoomLightOn = 
				new LightOnCommand(livingRoomLight);
		LightOffCommand livingRoomLightOff = 
				new LightOffCommand(livingRoomLight);
 
		remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
 
		remoteControl.onButtonWasPushed(0);
		remoteControl.offButtonWasPushed(0);
		System.out.println(remoteControl);
		remoteControl.undoButtonWasPushed();
		remoteControl.offButtonWasPushed(0);
		remoteControl.onButtonWasPushed(0);
		System.out.println(remoteControl);
		remoteControl.undoButtonWasPushed();

		CeilingFan ceilingFan = new CeilingFan("Living Room");
   
		CeilingFanMediumCommand ceilingFanMedium = 
				new CeilingFanMediumCommand(ceilingFan);
		CeilingFanHighCommand ceilingFanHigh = 
				new CeilingFanHighCommand(ceilingFan);
		CeilingFanOffCommand ceilingFanOff = 
				new CeilingFanOffCommand(ceilingFan);
  
		remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff);
		remoteControl.setCommand(1, ceilingFanHigh, ceilingFanOff);
   
		remoteControl.onButtonWasPushed(0);
		remoteControl.offButtonWasPushed(0);
		System.out.println(remoteControl);
		remoteControl.undoButtonWasPushed();
  
		remoteControl.onButtonWasPushed(1);
		System.out.println(remoteControl);
		remoteControl.undoButtonWasPushed();
	}
}