GOF23设计模式day87:结构型模式和行为型模式

2019-11-20  本文已影响0人  开源oo柒

一、结构模式

1.代理模式:

通过代理,控制对对象的访问;可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。

在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

抽象角色:
定义代理角色和真实角色的公共对外方法
真实角色:
实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。关注真正的业务逻辑!
代理角色:
实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

安全代理:屏蔽对真实角色的直接访问。
远程代理:通过代理类处理远程方法调用(RMI)。
延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。

1.1静态代理:
public interface Star {
    void confer();
    
    void contract();
    
    void ticket();
    
    void sing();
    
    void money();
}
public class RealStar implements Star{

    @Override
    public void confer() {
        System.out.println("RealStar.confer()");
    }

    @Override
    public void contract() {
        System.out.println("RealStar.contract()");
    }

    @Override
    public void ticket() {
        System.out.println("RealStar.ticket()");
    }

    @Override
    public void sing() {
        System.out.println("RealStar.sing()");
    }

    @Override
    public void money() {
        System.out.println("RealStar.money()");
    }
}
public class ProxyStar implements Star {

    private Star realStar;
    
    public ProxyStar(Star realStar) {
        super();
        this.realStar = realStar;
    }

    @Override
    public void confer() {
        System.out.println("ProxyStar.confer()");
    }

    @Override
    public void contract() {
        System.out.println("ProxyStar.contract()");
    }

    @Override
    public void ticket() {
        System.out.println("ProxyStar.ticket()");
    }

    @Override
    public void sing() {
        realStar.sing();
    }

    @Override
    public void money() {
        System.out.println("ProxyStar.money()");
    }
}
public class Client {
    public static void main(String[] args) {
        Star real = new RealStar();
        Star proxy = new ProxyStar(real);
        
        proxy.confer();
        proxy.contract();
        proxy.ticket();
        proxy.sing();
        proxy.money();
    }
}
结果
1.2动态代理:

动态代理(动态生成代理类)
• JDK自带的动态代理:
java.lang.reflect.Proxy:动态生成代理类和对象
java.lang.reflect.InvocationHandler(处理器接口):可以通过invoke方法实现对真实角色的代理访问。每次通过Proxy生成代理类对象对象时都要指定对应的处理器对象。
• javaassist字节码操作库实现。
• CGLIB。
• ASM(底层使用指令,可维护性较差)。

抽象角色中(接口)声明的所以方法都被转移到调用处理器一个集中的方
法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

struts2中拦截器的实现;
数据库连接池关闭处理;
Hibernate中延时加载的实现;
mybatis中实现拦截器插件;
AspectJ的实现;
spring中AOP的实现:日志拦截、声明式事务处理;
web service;

AOP(Aspect-Oriented Programming,面向切面的编程)它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。

示例

切面(Aspect):其实就是共有功能的实现。
通知(Advice):是切面的具体实现。
连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。
切入点(Pointcut):用于定义通知应该切入到哪些连接点上。
目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。
代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。
织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。

public interface Star {
    void confer();
    
    void contract();
    
    void ticket();
    
    void sing();
    
    void money();
}
public class RealStar implements Star{

    @Override
    public void confer() {
        System.out.println("RealStar.confer()");
    }

    @Override
    public void contract() {
        System.out.println("RealStar.contract()");
    }

    @Override
    public void ticket() {
        System.out.println("RealStar.ticket()");
    }

    @Override
    public void sing() {
        System.out.println("RealStar.sing()");
    }

    @Override
    public void money() {
        System.out.println("RealStar.money()");
    }
}
public class StarHandler implements InvocationHandler {

    Star realStar;

    public StarHandler(Star realStar) {
        super();
        this.realStar = realStar;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        System.out.println("真正的方法执行前!");
        System.out.println("签合同,预付款!");
        if(method.getName().equals("sing")) {
            object = method.invoke(realStar, args);
        }
        System.out.println("真正的方法执行后!");
        System.out.println("收尾款!");
        return object;
    }
}
public class Client {
    public static void main(String[] args) {
        Star realStar = new RealStar();
        StarHandler starHandler = new StarHandler(realStar);
        
        Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] {Star.class} , starHandler);
        proxy.sing();
    }
}
结果

二、行为模式

1.责任链模式:

能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,否则传递给链上的下一个对象。

职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

Java中,异常机制就是一种责任链模式。一个try可以对应多个catch,当第一个catch不匹配类型,则自动跳到第二个catch。
Javascript语言中,事件的冒泡和捕获机制。Java语言中,事件的处理
采用观察者模式。
Servlet开发中,过滤器的链式处理。
Struts2中,拦截器的调用也是典型的责任链模式

公司里面,请假条的审批过程:
• 如果请假天数小于3天,主任审批
• 如果请假天数大于等于3天,小于10天,经理审批
• 如果大于等于10天,小于30天,总经理审批
• 如果大于等于30天,提示拒绝

public class LeaveRequest {
    private String empName;
    private int leaveDays;
    private String reason;
    
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public int getLeaveDays() {
        return leaveDays;
    }
    public void setLeaveDays(int leaveDays) {
        this.leaveDays = leaveDays;
    }
    public String getReason() {
        return reason;
    }
    public void setReason(String reason) {
        this.reason = reason;
    }
    public LeaveRequest(String empName, int leaveDays, String reason) {
        super();
        this.empName = empName;
        this.leaveDays = leaveDays;
        this.reason = reason;
    }
}
public abstract class Leader {
    protected String name;
    protected Leader nextLeader;// 责任链的后继对象

    public Leader(String name) {
        super();
        this.name = name;
    }
    //设置后继对象
    public void setNextLeader(Leader nextLeader) {
        this.nextLeader = nextLeader;
    }

    //处理请求的业务方法
    public abstract void handleRequest(LeaveRequest request);
}
public class Director extends Leader{

    public Director(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if(request.getLeaveDays()<3) {
            System.out.println("员工姓名:"+request.getEmpName()+"请假"+request.getLeaveDays()+"天,理由"+request.getReason());
            System.out.println("Director:"+this.name+"审批通过!");
        }else {
            if(this.nextLeader!=null) {
                this.nextLeader.handleRequest(request);
            }
        }
    }
}
public class Manager extends Leader{

    public Manager(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if(request.getLeaveDays()<10) {
            System.out.println("员工姓名:"+request.getEmpName()+"请假"+request.getLeaveDays()+"天,理由"+request.getReason());
            System.out.println("Manager:"+this.name+"审批通过!");
        }else {
            if(this.nextLeader!=null) {
                this.nextLeader.handleRequest(request);
            }
        }
    }
}
public class GeneralManager extends Leader{

    public GeneralManager(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if(request.getLeaveDays()<30) {
            System.out.println("员工姓名:"+request.getEmpName()+"请假"+request.getLeaveDays()+"天,理由"+request.getReason());
            System.out.println("GeneralManager:"+this.name+"审批通过!");
        }else {
            System.out.println("GeneralManager审核不通过!");
        }
    }
}
public class Client {
    public static void main(String[] args) {
        Leader a = new Director("张三");
        Leader b = new Manager("李四");
        Leader c = new GeneralManager("王五");
        
        //组织责任链关系
        a.setNextLeader(b);
        b.setNextLeader(c);
        
        //请假操作
        LeaveRequest lr = new LeaveRequest("admin", 9, "回家探亲!!!");
        a.handleRequest(lr);
        
    }
}
结果

2.策略模式:

策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某一问题。可以方便的更换算法或者增加新的算法。并且由客户端决定调用哪个算法。
本质:分离算法,选择实现。

某个市场人员接到单后的报价策略(CRM系统中常见问题)。报价策略很复杂。
一个系统需要动态地在几种算法中选择一种。

JAVASE中GUI编程中,布局管理;
Spring框架中,Resource接口,资源访问策略;
javax.servlet.http.HttpServlet#service();

某个市场人员接到单后的报价策略(CRM系统中常见问题)。报价策略很复杂,可以简单作如下分类:
• 普通客户小批量报价
• 普通客户大批量报价
• 老客户小批量报价
• 老客户大批量报价

public interface Strategy {
    public double getPrice(double standardPrice);
}
public class OldCustomerManyStrategy implements Strategy {

    @Override
    public double getPrice(double standardPrice) {
        System.out.println("老顾客!打7折");
        return standardPrice*0.7;
    }
}
public class OldCustomerfewStrategy implements Strategy {

    @Override
    public double getPrice(double standardPrice) {
        System.out.println("老顾客!打8.5折");
        return standardPrice*0.85;
    }
}

public class NewCustomerfewStrategy implements Strategy {

    @Override
    public double getPrice(double standardPrice) {
        System.out.println("不打折!原价");
        return standardPrice;
    }
}
public class NewCustomerManyStrategy implements Strategy {

    @Override
    public double getPrice(double standardPrice) {
        System.out.println("打折9!");
        return standardPrice*0.9;
    }
}
/**
 * 负责和具体的策略类交互
 * @author zhang
 *
 */
public class Content {
    private Strategy strategy;// 当前采用的算法对象

    public Content(Strategy strategy) {
        super();
        this.strategy = strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public void pringPrice(double s) {
        System.out.println("你的报价:"+strategy.getPrice(s));
    }
}
public class Client {
    public static void main(String[] args) {
        Strategy s = new OldCustomerManyStrategy();
        Content content = new Content(s);
        content.pringPrice(100);
    }
}
结果

3.模板模式:

一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。

方法的回调:把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。
钩子方法就像一个钩子一样,执行时,挂哪个子类的方法就调用哪个。

Don't call me, I will call you;
在好莱坞,当艺人把简历递交给好莱坞的娱乐公司时,所能做的就是等待,整个过程都是娱乐公司控制,演员只能被动的服务安排,在需要的时候由公司具体安排。

public abstract class BankTemplateMethod {
    // 具体方法
    public void takeNumber() {
        System.out.println(" 取号排队");
    }

    public abstract void transact(); // 办理具体的业务 // 钩子方法

    public void evaluate() {
        System.out.println(" 反馈评分");
    }

    public final void process() {
        this.takeNumber();
        this.transact();
        this.evaluate();
    }
}
public class Client {
    public static void main(String[] args) {
        BankTemplateMethod t = new Test();
        t.process();
        System.out.println("-------------");
        BankTemplateMethod btl = new BankTemplateMethod() {

            @Override
            public void transact() {
                System.out.println("我要存钱!");
            }
        };
        btl.process();
    }
}

class Test extends BankTemplateMethod {

    @Override
    public void transact() {
        System.out.println("我要取钱!");
    }
}
示例

4.观察者模式:

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
观察者和被观察者是抽象耦合的。建立了一套触发机制。

聊天室程序的,服务器转发给所有客户端;
网络游戏(多人联机对战)场景中,服务器将客户端的状态进行分发;
邮件订阅;
Servlet中,监听器的实现;
Android中,广播机制;

观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。

public interface Observer {
    void update(Subject subject);
}
public class ObserverA implements Observer {

    private int myState;

    @Override
    public void update(Subject subject) {
        myState = ((ConcreteSubject)subject).getState();
    }

    public int getMyState() {
        return myState;
    }

    public void setMyState(int myState) {
        this.myState = myState;
    }
}
public class Subject {
    protected List<Observer> list = new ArrayList<Observer>();
    
    public void registerObserver(Observer obs) {
        list.add(obs);
    }
    public void removeObserver(Observer bos) {
        list.add(bos);
    }
    public void allObserver() {
        for (Observer observer : list) {
            observer.update(this);
        }
    }
}
public class ConcreteSubject extends Subject {
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        this.allObserver();
    }
}
public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        
        ObserverA ob1 = new ObserverA();
        ObserverA ob2 = new ObserverA();
        ObserverA ob3 = new ObserverA();
        
        subject.registerObserver(ob1);
        subject.registerObserver(ob2);
        subject.registerObserver(ob3);
        
        subject.setState(300);
        System.out.println(ob1.getMyState());
        System.out.println(ob2.getMyState());
        System.out.println(ob3.getMyState());
    }
}
结果
4.1使用JavaSE提供的

java.util.Observerable类和java.util.Observer接口

public class ConcreteSubject extends Observable{
    private int state;

    public void set(int s) {
        state = s;
        
        setChanged();
        notifyObservers(state);
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }
}
public class ObserverA implements Observer {
    private int myState;

    @Override
    public void update(Observable o, Object arg1) {
        myState = ((ConcreteSubject) o).getState();
    }

    public int getMyState() {
        return myState;
    }

    public void setMyState(int myState) {
        this.myState = myState;
    }
}
public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        
        ObserverA ob1 = new ObserverA();
        ObserverA ob2 = new ObserverA();
        ObserverA ob3 = new ObserverA();
        
        subject.addObserver(ob1);
        subject.addObserver(ob2);
        subject.addObserver(ob3);
        
        subject.set(3000);
        System.out.println(ob1.getMyState());
        System.out.println(ob2.getMyState());
        System.out.println(ob3.getMyState());
    }
}
结果
上一篇 下一篇

猜你喜欢

热点阅读