委派模式和策略模式笔记

委派模式和策略模式

委派模式

什么是委派模式?

维基百科对委派模式的解释是:委派模式(delegation pattern)是软件设计模式中的一项基本技巧。在委派模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来代理。

委派模式的基本作用就是负责任务的调用和分配任务,跟代理模式很像,可以看做是一种特殊情况下的静态代理的全权代理,但是代理模式注重过程,而委派模式注重结果。委派模式在Spring中应用非常多,大家常用的DispatcherServlet其实就是用到了委派模式。现实生活中也常有委派的场景发生。例如:教室要进行大扫除,老师(Teacher)布置任务给班长(Monitor),班长再根据任务分配给学生(Student),我们以代码的形式进行模拟一下。

/**
 * @author: Winston
 * @createTime: 2021/6/24
 *
 * 老师
 */
public class Teacher {


    /**
     * 给班长下发命令
     * @param command
     * @param monitor
     */
    public void command(String command, Monitor monitor){
        monitor.doing(command);
    }

}

/**
 * @author: Winston
 * @createTime: 2021/6/24
 * 学生听指令的接口
 */
public interface IStudent {

    /**
     * 根据指令做事
     * @param command
     */
    void doing(String command);

}


/**
 * @author: Winston
 * @createTime: 2021/6/24
 *
 * 班长
 */
public class Monitor implements IStudent{

    /**
     * map用来存放接收指令的学生,key是指令  map 是学生
     */
    private Map<String,IStudent>  studentMap = new HashMap<>();

    public Monitor(){
        studentMap.put("扫地",new StudentA());
        studentMap.put("擦黑板",new StudentB());
    }

    /**
     * 班长不干活,根据指令给学生分派任务
     * @param command
     */
    @Override
    public void doing(String command) {
        studentMap.get(command).doing(command);
    }
}

/**
 * @author: Winston
 * @createTime: 2021/6/24
 */
public class StudentA implements IStudent {

    @Override
    public void doing(String command) {
        System.out.println("我是StudentA,我大扫除的职责是,"+command);
    }
}

/**
 * @author: Winston
 * @createTime: 2021/6/24
 */
public class StudentB implements IStudent {

    @Override
    public void doing(String command) {
        System.out.println("我是StudentB,我大扫除的职责是,"+command);
    }
}

测试类

/**
 * @author: Winston
 * @createTime: 2021/6/24
 */
public class DelegateTest {
    public static void main(String[] args) {
        //客户请求(Teacher)、委派者(Monitor)、被被委派者(Student)
        //委派者要持有被委派者的引用
        //代理模式注重的是过程, 委派模式注重的是结果
        //策略模式注重是可扩展(外部扩展),委派模式注重内部的灵活和复用
        //委派的核心:就是分发、调度、派遣
        //委派模式:就是静态代理和策略模式一种特殊的组合
        new Teacher().command("扫地", new Monitor());
    }
}


运行结果:我是StudentA,我大扫除的职责是,扫地

委派模式在SpringMVC源码中的体现

下面我们来简单模拟一下SpringMVC的DispatcherServlet是怎么实现委派模式的。先创建几个Controller

/**
 * @author: Winston
 * @createTime: 2021/6/24
 */
public class UserController {

    public void findUserById(String id){
    }
}

/**
 * @author: Winston
 * @createTime: 2021/6/24
 */
public class OrderController {

    public void findOrderById(String id){
    }
}
/**
 * @author: Winston
 * @createTime: 2021/6/24
 */
public class IndexController {

    public void index(){

    }
}

创建一个DispatcherServlet用于分发请求


/**
 * 这个类就相当于是班长角色
 * @author: Winston
 * @createTime: 2021/6/24
 */
public class DispatcherServlet extends HttpServlet {
    private void doDispatcher(HttpServletRequest request, HttpServletResponse response){

        String requestURI = request.getRequestURI();
        String id = request.getParameter("id");


        // 根据uri判断分发请求到Controller
        if("findUserById".equals(requestURI)){
            new UserController().findUserById(id);
        }else if("findOrderById".equals(requestURI)){
            new OrderController().findOrderById(id);
        }else if("index".equals(requestURI)){
            new IndexController().index();
        }else {
            try {
                response.getWriter().write("404 NOT FOUND");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

配置web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
    <display-name>Gupao Web Application</display-name>


    <servlet>
        <servlet-name>delegateServlet</servlet-name>
        <servlet-class>com.gupaoedu.vip.pattern.delegate.mvc.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>delegateServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>


</web-app>


小结

一个模拟委派模式的简单DispatcherServlet就写完了。Spring中有许多地方都用到了委派模式,我们可以通过命名来识别,只要是以Delegate结尾的都是事先了委派模式。例如:BeanDefinitionParserDelegate 根据不同类型委派不同逻辑解析BeanDefinition。

策略模式

策略模式概念

首先了解一下策略模式的概念,在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

策略模式的应用场景

1、假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。

2、一个系统需要动态地在几种算法中选择一种。

案例一

上面对策略模式的介绍都比较抽象不太好理解,举个生活中的小例子,在我们进行网上购物时如果遇到一些活动商家会给商品以某些形式降价,比如优惠券、拼团、返现。下面我们通过用代码来模拟一下。

首先创建一个促销活动Promotion接口,所有的降价形式都要实现这个接口。

/**
 * @author: Winston
 * @createTime: 2021/6/25
 *
 * 促销活动
 */
public interface Promotion {

    /**
     * 活动内容
     */
    void activity();
}

无优惠活动的 EmptyActivity类

public class EmptyActivity implements Promotion{
    @Override
    public void activity() {
        System.out.println("无促销活动");
    }
}

优惠券活动

public class CouponActivity implements Promotion {
    @Override
    public void activity() {
        System.out.println("优惠券立减20");
    }
}

返现活动

public class CashbackActivity implements Promotion {
    @Override
    public void activity() {
        System.out.println("购买立马返现15");
    }
}

组团活动

public class GroupActivity implements Promotion {
    @Override
    public void activity() {
        System.out.println("两人拼团立减25");
    }
}

促销方案类PromotionActivity

/**
 * @author: Winston
 * @createTime: 2021/6/25
 *
 * 举办的促销活动
 */
public class PromotionActivity {
    private Promotion promotion;

    public PromotionActivity(Promotion promotion) {
        this.promotion = promotion;
    }


    public void execute(){
        promotion.activity();
    }
}

测试类:

public class PromotionTest {
    public static void main(String[] args) {
        // 不同活动对应不同的优惠策略,默认策略是无优惠
        PromotionActivity promotionActivity = null;
        String promotionKey = "anniversary";
        if ("doubleEleven".equals(promotionKey)) {
            // 双十一活动,优惠券
            promotionActivity = new PromotionActivity(new CouponActivity());
        } else if ("activity618".equals(promotionKey)) {
            // 618,返现
            promotionActivity = new PromotionActivity((new CashbackActivity()));
        } else if ("anniversary".equals(promotionKey)) {
            // 店庆,组团
            promotionActivity = new PromotionActivity((new GroupActivity()));
        } else {
            promotionActivity = new PromotionActivity(new EmptyActivity());
        }
        promotionActivity.execute();
    }
}

从上面的测试代码可以看出,如果又增加了一个促销活动,那么我们就又要加上新活动,增加if else,相当于又修改了业务代码,那么又要进行测试,如此一来工作量难免是重复且耗时的,下面我们结合工厂模式和单例模式对其进行改造,在这里说一下,设计模式一般都不是单独出现的,而是结合使用。

创建一个存放活动策略key的枚举,PromotionEnum

/**
 * @author: Winston
 * @createTime: 2021/6/25|
 *
 * 促销活动策略的enum
 */
public enum PromotionEnum {
    COUPON_ACTIVITY("优惠券活动","COUPON_ACTIVITY"),
    CASHBACK_ACTIVITY("返现活动","CASHBACK_ACTIVITY"),
    GROUP_ACTIVITY("组团活动","GROUP_ACTIVITY")
    ;


    /**
     * 活动名称
     */
    private String activityName;
    /**
     * 活动key
     */
    private String promotionKey;

    PromotionEnum(String activityName, String promotionKey) {
        this.activityName = activityName;
        this.promotionKey = promotionKey;
    }

    public String getActivityName() {
        return activityName;
    }

    public void setActivityName(String activityName) {
        this.activityName = activityName;
    }

    public String getPromotionKey() {
        return promotionKey;
    }

    public void setPromotionKey(String promotionKey) {
        this.promotionKey = promotionKey;
    }
}

创建促销策略工厂PromotionFactory

/**
 * @author: Winston
 * @createTime: 2021/6/25
 * 促销策略工厂
 */
public class PromotionFactory {
    /**
     * 活动
     */
    private static Promotion promotion;
    /**
     * 存放活动策略的map,Key是活动名称,value是具体活动
     */
    private static Map<String, Promotion> promotionMap = new HashMap<>();
    /**
     * 默认策略,无优惠
     */
    private static final EmptyActivity emptyActivity = new EmptyActivity();

    static {
        promotionMap.put(PromotionEnum.COUPON_ACTIVITY.getPromotionKey(), new CouponActivity());
        promotionMap.put(PromotionEnum.CASHBACK_ACTIVITY.getPromotionKey(), new CashbackActivity());
        promotionMap.put(PromotionEnum.GROUP_ACTIVITY.getPromotionKey(), new GroupActivity());
    }

    /**
     * 根据活动key拿到对应的活动
     * @param key
     * @return
     */
    public static Promotion getPromotionByKey(String key) {
        promotion = promotionMap.get(key);

        return promotion == null ? emptyActivity : promotion;
    }

}

测试类:

public class OptimizePromotionTest {
    public static void main(String[] args) {
        Promotion promotion = PromotionFactory.getPromotionByKey(PromotionEnum.COUPON_ACTIVITY.getPromotionKey());
        promotion.activity();
    }
}

案例二

通过第一个案例,我们对策略模式有了一点了解,下面再举一个例子来加深对策略模式的印象。在我们点外卖进行付款时,往往有多种支付方式,比如微信支付、支付宝支付、银行卡支付、QQ支付等,这些支付方式的选择其实也是策略模式的一种体现,下面我们通过代码来进行模拟。

创建一个Payment抽象类,定义支付规范和支付逻辑:

/**
 * @author: Winston
 * @createTime: 2021/6/25
 * <p>
 * 支付工具中所具有的方法
 */
public abstract class Payment {
    /**
     * 支付类型
     *
     * @return
     */
    public abstract String getName();

    /**
     * 余额查询
     */
    protected abstract Double queryBalance();

    /**
     * 支付方法
     *
     * @param amount  支付金额
     * @param balance 余额
     */
    public PayState pay(Double amount, Double balance) {
        if (balance >= amount) {
            return new PayState(200, "支付成功");
        } else {
            return new PayState(500, "支付失败,余额不足");
        }
    }

}

创建几种支付方式,微信支付、支付宝支付、qq支付、银行卡支付

/**
 * @author: Winston
 * @createTime: 2021/6/25
 */
public class WechatPay extends Payment {


    @Override
    public String getName() {
        return "微信支付";
    }

    @Override
    protected Double queryBalance() {
        return 14.43D;
    }
}
/**
 * @author: Winston
 * @createTime: 2021/6/25
 */
public class AliPay extends Payment {


    @Override
    public String getName() {
        return "支付宝支付";
    }

    @Override
    protected Double queryBalance() {
        return 561.24D;
    }
}
/**
 * @author: Winston
 * @createTime: 2021/6/25
 */
public class QqPay extends Payment {


    @Override
    public String getName() {
        return "qq支付";
    }

    @Override
    protected Double queryBalance() {
        return 5.43D;
    }
}
/**
 * @author: Winston
 * @createTime: 2021/6/25
 */
public class CardPay extends Payment {


    @Override
    public String getName() {
        return "银行卡支付";
    }

    @Override
    protected Double queryBalance() {
        return 20051.15D;
    }
}

创建一个支付状态的包装类PayState

/**
 * @author: Winston
 * @createTime: 2021/6/25
 */
public class PayState {
    /**
     * 状态码
     */
    private int code;

    /**
     * 状态信息
     */
    private String msg;

    public PayState(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "PayState{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                '}';
    }
}

创建支付策略管理类:


/**
 * @author: Winston
 * @createTime: 2021/6/25
 * 支付策略管理
 */
public class PayStrategy {
    public static final String ALI_PAY= "ALI_PAY";
    public static final String WECHAT_PAY= "WECHAT_PAY";
    public static final String CARD_PAY= "CARD_PAY";
    public static final String QQ_PAY= "QQ_PAY";
    public static final String DEFAULT_PAY= ALI_PAY;

    // 存放支付策略的map
    private static Map<String,Payment> paymentMap = new HashMap<>();

    static {
        paymentMap.put(ALI_PAY,new AliPay());
        paymentMap.put(WECHAT_PAY,new WechatPay());
        paymentMap.put(CARD_PAY,new CardPay());
        paymentMap.put(QQ_PAY,new QqPay());
    }

    public static Payment get(String payKey){
        if(!paymentMap.containsKey(payKey)){
            return paymentMap.get(DEFAULT_PAY);
        }
        return paymentMap.get(payKey);
    }

}

创建订单类,模拟下单支付时的操作

/**
 * @author: Winston
 * @createTime: 2021/6/25
 * 订单类
 */
public class Order {
    /**
     * 订单id
     */
    private String id;
    /**
     * 订单金额
     */
    private Double amount;

    public Order(String id, Double amount) {
        this.id = id;
        this.amount = amount;
    }

    public void pay() {
        pay(PayStrategy.DEFAULT_PAY);
    }

    /**
     * 使用指定支付方式支付
     *
     * @param payKey
     */
    public void pay(String payKey) {
        System.out.println("订单编号是:" + this.id);
        System.out.println("支付金额为:" + this.amount);
        Payment payment = PayStrategy.get(payKey);
        System.out.println("支付方式:" + payment.getName());
        PayState pay = payment.pay(this.amount, payment.queryBalance());
        System.out.println(pay);
    }

}

测试类:

public class PaymentTest {
    public static void main(String[] args) {
        System.out.println("开始下单点外卖:");
        Order order = new Order("10001", 21.31D);
        order.pay(PayStrategy.WECHAT_PAY);
    }
}

运行结果:

开始下单点外卖:
订单编号是:10001
支付金额为:21.31
支付方式:微信支付
PayState{code=500, msg='支付失败,余额不足'}

策略模式在JDK源码中的体现

Comparator接口中的compare()方法,就是一个策略抽象实现。

    int compare(T o1, T o2);

Comparator 抽象下面有非常多的实现类,我们经常会把 Comparator 作为参数传入作
为排序策略,例如 Arrays 类的 parallelSort 方法等:

public class Arrays {
...
public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> cmp) {
...
}
...
}

还有TreeMap的构造方法:

public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
    ...
    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }
    ...
}

策略模式的优缺点

优点:

  • 策略模式符合开闭原则
  • 避免使用多重条件转移语句,如if...else...、switch
  • 使用策略模式可以提高算法的保密性和安全性

缺点:

  • 客户端必须知道所有的策略,并且自行决定使用哪一个策略类
  • 代码中会产生非常多的策略类,增加维护难度

委派模式与策略模式综合应用

在委派模式中我们写了一个例子模仿了SpringMVC的DispatcherServlet,在那个例子中我们用了很多的if...else语句,在实际项目中Controller数量往往很大,如果都用if..else来写的话,那么不仅工作量大,而且出错的可能性也很大,下面我们使用委派模式和策略模式将它进行改造。

创建一个Handler类,用于存Method和url对应的关系

/**
 * @author: Winston
 * @createTime: 2021/6/25
 *
 * 保存Controller的一些信息,将url和method的关系绑定
 */
public class Handler {

    /**
     * controller的实例
     */
    private Object controller;

    /**
     * 存放方法
     */
    private Method method;

    /**
     * 对应映射方法的url
     */
    private String url;


    public Handler(Object controller, Method method, String url) {
        this.controller = controller;
        this.method = method;
        this.url = url;
    }

    public Object getController() {
        return controller;
    }

    public void setController(Object controller) {
        this.controller = controller;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

之前写过的三个controller

public class UserController {

    public void findUserById(String id){
    }
}


public class OrderController {

    public void findOrderById(String id){
    }
}

public class IndexController {

    public void index(){

    }
}

改造的servlet,重写init方法用于模拟在启动时将各个controller信息保存到Handler中去,代码如下:

/**
 * 这个类就相当于是班长角色
 *
 * @author: Winston
 * @createTime: 2021/6/24
 */
public class DispatcherServlet extends HttpServlet {

    // 初始化所有controller的信息存到handlerList中
    public static List<Handler> handlerList = new ArrayList<>();

    /**
     * 模拟controller初始化时将信息存到handlerList中
     */
    @Override
    public void init() throws ServletException {
        Class<UserController> userControllerClass = UserController.class;
        Class<OrderController> orderControllerClass = OrderController.class;
        Class<IndexController> indexControllerClass = IndexController.class;
        try {
            Handler userHandler = new Handler(userControllerClass.newInstance(),
                    userControllerClass.getMethod("findUserById", new Class[]{String.class}), "/web/findUserById");
            Handler orderHandler = new Handler(orderControllerClass.newInstance(),
                    orderControllerClass.getMethod("findOrderById", new Class[]{String.class}), "/web/findOrderById");
            Handler indexHandler = new Handler(indexControllerClass.newInstance(),
                    indexControllerClass.getMethod("index", null), "/web/index");
            // 将handler添加到list中
            handlerList.add(userHandler);
            handlerList.add(orderHandler);
            handlerList.add(indexHandler);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doDispatcher(req, resp);
    }


    private void doDispatcher(HttpServletRequest request, HttpServletResponse response) {
        // 获取url
        String requestURI = request.getRequestURI();
        // 要执行的handler
        Handler handler = null;
        // 根据url获取handler
        for (Handler h : handlerList) {
            if(h.getUrl().equals(requestURI)){
                handler = h;
                break;
            }
        }
        if(handler == null){
            try {
                response.getWriter().write("Not found 404!");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
        // 执行方法的结果
        Object result = null;
        try {
            // 根据获取到的执行器利用反射执行方法,实际没那么简单,这里简单模拟不用深究
            result =  handler.getMethod().invoke(handler.getController(),request.getParameter("id"));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        // 将结果返回
        try {
            response.getWriter().write(result.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356

推荐阅读更多精彩内容

  • 1. 委派模式 1.1 委派模式的简介 委派模式不属于 GOF23 种设计模式中。 委派模式( Delegate ...
    AnonyStar阅读 476评论 0 0
  • 委派模式(Delegate Pattern) 介绍:委派模式(Delegate Pattern)的基本作用就是负责...
    曾是少年_1478阅读 256评论 0 0
  • 委派模式 委派模式不属于GOF23种设计模式中。委派模式(DelegatePattern)的基本作用就是负责任务的...
    javacoo阅读 241评论 0 1
  • 委派模式的定义及应用场景 委派模式不属于 GOF23 种设计模式中。委派模式(Delegate Pattern)的...
    提玛欧斯阅读 385评论 0 0
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 125,189评论 2 7