1 策略模式:定义一系列算法的方法,所有的算法功能相同但是实现不同。
设计原则:
1、封装变化
2、多用组合,少用继承
3、针对接口编程,不针对实现编程
示例类图:
如上类图所示:鸭子有两个可能的行为--飞行(FlyBehavior)和呱呱叫(QuackBehavior),为适应不
同的鸭子这两种行为的不同方式,这是会发生“变化”的部分,将它们封装起来,形成接口。然后
设计不同的策略类继承自行为接口,不同的鸭子都组合一个(FlyBehavior)和(QuackBehavior),以组合的方式形成一个具体鸭子。而在某个具体鸭子中,真正起作用的是
FlyBehavior和QuackBehavior的策略类即子类。
部分代码展示:
public abstract class Duck {
protected FlyBehavior flyBehavior;
protected QuackBehavior quackBehavior;
public abstract void display();
public void swim(){
System.out.println("I can swim");
}
public void fly(){
flyBehavior.fly();
}
public void quack(){
quackBehavior.quack();
}
public void setFlyBehavior(FlyBehavior flyBehavior){
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior){
this.quackBehavior = quackBehavior;
}
}
public class MallardDuck extends Duck {
public MallardDuck(){
this.flyBehavior = new FlyWithWings();
this.quackBehavior = new Quack();
}
@Override
public void display(){
System.out.println("MallardDuck display");
}
}
2 装饰器模式:将核心功能与装饰器功能分开,以便动态添加功能。
涉及的设计原则:
1,对拓展开放,对修改关闭
示例类图:
如上类图所示,所有的类都是Beverage的子类,因此所有的类都可以用Beverage的引用来指
向,因此可以利用Beverage beverage = new Mocha(Beverage beverage)来进行反复为一杯咖
啡中添加mocha或者whip或者soy。
部分示例代码:
public abstract class Beverage {
String description = "UnKnow Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
public class DarkRoast extends Beverage{
public DarkRoast(){
description = "DarkRoast ";
}
@Override
public double cost() {
return 0.89;
}
}
public abstract class CondimentDerator extends Beverage{
public abstract String getDescription();
}
public class Mocha extends CondimentDerator{
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + " Mocha";
}
@Override
public double cost() {
return beverage.cost() + 0.15;
}
}
public class Whip extends CondimentDerator{
Beverage beverage;
public Whip(Beverage beverage){
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + " Whip";
}
@Override
public double cost() {
return beverage.cost()+0.12;
}
}
public class Test {
public static void main(String[] args) {
Beverage beverage1 = new DarkRoast();
beverage1 = new Mocha(beverage1);
beverage1 = new Mocha(beverage1);
beverage1 = new Whip(beverage1);
System.out.println("超优深焙咖啡,双份摩卡,打泡:" + beverage1.getDescription());
System.out.println("cost:" + beverage1.cost() + "$");
Beverage beverage2 = new HouseBlend();
beverage2 = new Soy(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println("首选咖啡:" + beverage2.getDescription());
System.out.println("cost : " + beverage2.cost() + "$");
}
}
3 代理模式
3.1 远程代理模式:利用javaRMI作代理,使另一个JVM上运行的对象可以在本地JVM上获取到。
图形示例:
客户端要获取服务端的某个对象,实际上是向RMI registry做请求,获取到服务器上的某个远程
对象,而这个远程对象又是服务器在编译的时候注册到RMI上的。因此,在客户端和服务端之间
就建立了一个以RMI registry做代理的通讯。
部分代码示例:
(1) 服务端将某个对象设置为远程对象,需要拓展(或继承)Remote接口---在java.rmi.*包中
public interface GumballMachineRemote extends Remote {
int getCount()throws RemoteException;
String getLocation() throws RemoteException;
String getState() throws RemoteException;
}
(2)在服务端写远程对象的具体实现,,java.rmi.server.UnicastRemoteObject 所有可以被远程调用的对象都必须扩展该类
public class GumballMachine extends UnicastRemoteObject implements GumballMachineRemote {
private String location;
private int count;
public GumballMachine(String location,int count) throws RemoteException{
this.count = count;
this.location = location;
}
@Override
public int getCount() throws RemoteException {
return count;
}
@Override
public String getLocation() throws RemoteException {
return location;
}
@Override
public String getState() throws RemoteException {
return "state";
}
}
(3) 服务端将远程对象注册进入RMI registry中
public class GumballMachineTestDrive {
public static void main(String[] args) {
try {
//启动RMI注册服务,指定端口为1099 (1099为默认端口)
LocateRegistry.createRegistry(1099);
//创建服务对象
GumballMachineRemote gumballMachine = new GumballMachine("10.0.0.1",5);
//把gumballMachine注册到RMI注册服务器上,命名为gumballMachine
Naming.rebind("gumballMachine",gumballMachine);
}catch (RemoteException | MalformedURLException e){
e.printStackTrace();
}
}
}
(4) 书写客户端程序
public class GumballMonitor {
GumballMachineRemote gumballMachineRemote;
public GumballMonitor(GumballMachineRemote machineRemote){
this.gumballMachineRemote = machineRemote;
}
public void report(){
try{
System.out.println("Gumball Machine:" + gumballMachineRemote.getLocation());
System.out.println("Current inventory:" + gumballMachineRemote.getCount() + " gumballs");
System.out.println("Current state:" + gumballMachineRemote.getState());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
(5) 客户端调用测试:
public class GumballMonitorTestDrive {
public static void main(String[] args) {
try {
GumballMachineRemote gumballMachineRemote = (GumballMachineRemote) Naming.lookup("rmi://127.0.0.1:1099/gumballMachine");
GumballMonitor gumballMonitor = new GumballMonitor(gumballMachineRemote);
gumballMonitor.report();
} catch (NotBoundException | MalformedURLException | RemoteException e) {
e.printStackTrace();
}
}
}
3.2 虚拟代理模式:对于一些占用系统资源较多或者加载时间较长的对象,可以给这些对象
提供一个虚拟代理。在真实对象创建成功之前虚拟代理扮演真实对象的替身,而当真实对象创建
之后,虚拟代理将用户的请求转发给真实对象。
图形示例:
如图所示:在客户端发出请求的时候,首先是代理进行处理,代理在开始创建对象的同时,会给
客户端提供一个返回值,而不是让客户端进行无意义地等待中,知道真实对象创建成功后,则会
将请求委托给真实对象。
图片处理的时候,用虚拟代码显示良好信息的代码示例:
public class ImageProxy implements Icon {
private ImageIcon imageIcon;
private URL imageURL;
private Thread retrievalThread;
private boolean retrieving = false;
@Override
public void paintIcon(final Component c, Graphics g, int x, int y) {
if(imageIcon != null){
imageIcon.paintIcon(c,g,x,y);
}else {
g.drawString("Loading image....",x+300,y+300);
if(!retrieving){
retrieving = true;
retrievalThread = new Thread(new Runnable() {
@Override
public void run() {
try{
imageIcon = new ImageIcon(imageURL,"CD Cover");
c.repaint();
}catch (Exception e){
e.printStackTrace();
}
}
});
retrievalThread.start();
}
}
}
@Override
public int getIconWidth() {
if(imageIcon != null){
return imageIcon.getIconWidth();
}else {
return 800;
}
}
@Override
public int getIconHeight() {
if(imageIcon != null){
return imageIcon.getIconHeight();
}else {
return 600;
}
}
}
在创建真实对象ImageIcon之前,会给客户端显示"Loading Image...”的提示信息
3.3 静态代理:静态代理是最简单的一种代理模式,在程序运行前,某个类的代理委托关系
已经确定好了。
类图示例:
代码示例:(出处:https://www.jianshu.com/p/a8aa6851e09e)
public interface Subject {
public void buyMac();
}
public class RealSubject implement Subject{
@Override
public void buyMac() {
System.out.println(”买一台Mac“);
}
}
public class Proxy implements Subject{
@Override
public void buyMac{
//引用并创建真实对象实例,即”我“
RealSubject realSubject = new RealSubject();
//调用真实对象的方法,进行代理购买Mac
realSubject.buyMac();
//代理对象额外做的操作
this.WrapMac();
}
public void WrapMac(){
System.out.println(”用盒子包装好Mac“);
}
}
public class ProxyPattern {
public static void main(String[] args){
Subject proxy = new Proxy();
proxy.buyMac();
}
}
3.4 动态代理(保护代理):在程序运行时动态创建一个代理类,实现一个或多个接口,并
将方法的调用转发到指定的类中。
类图:
创建动态代理类需要通过调用Proxy的静态方法newProxyInstance方法,即:
static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
InvocationHandler h)
ClassLoader loader:被代理类的类加载器(可以通过反射获取,如:person.getClass().getClassLoader())
Class<?>[] interfaces:被代理类要实现的接口列表(可以通过反射获取,如:person.getClass().getInterfaces())
InvocationHandler h:代理处理程序(即实现InvocationHandler接口的代理类)
创建一个代理类示例:
PersonBean personBean = (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader,
person.getClass().getInterfaces(),
new OwnerInvocationHandler(person))
动态代理的类都需要继承InvocationHandler类,这个类中只有一个方法:
Object invoke(Object proxy, Method method, Object[] args)
Ojbect proxy:表示需要代理的对象
Method method:表示要操作的方法
Object[] args:method方法所需要传入的参数(可能没有为,null.也可能有多个)
代码示例:
建立被代理类接口和实现类
public interface PersonBean {
String getName();
String getGender();
String getInterests();
int getHotOrNotRating();
void setName(String name);
void setGender(String gender);
void setInterests(String interests);
void setHotOrNotRating(int rating);
}
class PersonBeanImpl implements PersonBean{
private String name;
private String gender;
private String interests;
private int rating;
private int ratingCount = 0;
@Override
public String getName() {
return name;
}
@Override
public String getGender() {
return gender;
}
@Override
public String getInterests() {
return interests;
}
@Override
public int getHotOrNotRating() {
if(ratingCount == 0) return 0;
return (rating/ratingCount);
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void setGender(String gender) {
this.gender = gender;
}
@Override
public void setInterests(String interests) {
this.interests = interests;
}
建立动态代理类:
class NonOwnerInvocationHandler implements InvocationHandler {
private PersonBean personBean;
NonOwnerInvocationHandler(PersonBean personBean) {
this.personBean = personBean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if(method.getName().equals("setHotOrNotRating")) {
return method.invoke(personBean, args);
} else if(method.getName().startsWith("set")){
throw new IllegalAccessException();
}
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
class OwnerInvocationHandler implements InvocationHandler {
private PersonBean personBean;
OwnerInvocationHandler(PersonBean personBean){
this.personBean = personBean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try{
if(method.getName().startsWith("get")){
return method.invoke(personBean,args);
}else if(method.getName().equals("setHotOrNotRating")){
throw new IllegalAccessException();
}else if(method.getName().startsWith("set")){
return method.invoke(personBean,args);
}
}catch (InvalidParameterException e){
e.printStackTrace();
}
return null;
}
}
测试类:
public class MatchMakingTestDrive {
public static void main(String[] args) {
PersonBean person = new PersonBeanImpl();
person.setGender("male");
person.setName("richard");
person.setInterests("reading");
person.setHotOrNotRating(5);
System.out.println("has made personBean!");
PersonBean ownerPerson = getOwnerProxy(person);
try {
ownerPerson.setHotOrNotRating(1);
} catch (Exception e) {
System.out.println("owner can't setHotOrNotRating");
}
ownerPerson.setInterests("science");
PersonBean nonOwnerPerson = getNonOwnerProxy(person);
try {
nonOwnerPerson.setInterests("write");
} catch (Exception e) {
System.out.println("nonOwner can't setInterests");
}
nonOwnerPerson.setHotOrNotRating(10);
}
private static PersonBean getOwnerProxy(PersonBean person) {
return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new OwnerInvocationHandler(person));
}
private static PersonBean getNonOwnerProxy(PersonBean person) {
return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new NonOwnerInvocationHandler(person));
}
}
3.5 cglib动态代理:对于有接口的类,可以用上述动态代理,当某个实现类没有实现接口时,就需要用cglib动态代理。
原文见:http://blog.csdn.net/yakoo5/article/details/9099133/
代码示例:
被代理类:
public class SayHello {
public void say(){
System.out.println("hello everyone");
}
}
该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的
字节码,通过扩展父类的class来创建代理对象。intercept()方法拦截所有目标类方法的调用,obj
表示目标类的实例,method为目标类方法的反射对象,args为方法的动态入参,proxy为代理类
实例。proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
//实现MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
}
测试:
public class DoCGLib {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过生成子类的方式创建代理类
SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
proxyImp.say();
}
}
结果:
前置代理
hello everyone
后置代理
总结
策略模式是定义某个接口,以不同的实现类来代替实现某种功能,
这些实现类的功能是一样的,但是具体实现方式不同。
装饰器模式是定义不同的装饰类,这些装饰类都是核心类的子类,
同时核心类也是这些装饰类的一个属性,可以动态地为该核心类动态添加不同的功能模块(装饰类)
代理模式是将某个具体类包装起来,通过代理类来处理消费方和生产方之间的交互,
同时也可以在代理类中添加一些额外的操作。