headfirst设计格局(4)—工厂格局

背景

 

电商平台平日召开有些秒杀场景的位移来对货物举行优惠,来拉动上上下下集团的影响力;而秒杀活动一般是在特定的年华、特定的货品举办限制的行销抢购,这样会吸引大量的用户展开抢购,并在活动约定的岁月点同时的拓展秒杀抢购;这样也就形成如下特点:

1)大量用户同一时间同时展开抢购,网站弹指之间访问流量剧增。

2)访问请求数量远远大于库存数量,唯有少部分用户可以秒杀成功。

3)购物车平素下单减库存。

4)秒杀商品下单减库存。

 

开篇

概念

从地点的背景中大家需要面对的题材虽然,针对于电商平台如何让它可以在那种高并发、大流量的伸手下让其能够平静、满负荷的周转。所以这就需要引入流量监控平台,它亦可实时领会各样服务器的运行参数、各类业务单元的呼吁数量;随时为负责人提供明晰的数目参考,以备调度。

 

无时无刻逛知乎,就是狠不下心来写篇博客,忙是一方面,不过说忙能有多忙啊,都有时间逛天涯论坛,写篇博客的刻钟都不曾?(这还真不佳说)

何以是流量监控

流量监控,又可以明白为一种流量整形,是一个电脑网络的网络交通管理技术,从而延缓部分或有所数据包,使之符合人们所需的网络交通规则,速率限制的中间一种重大格局。

网络流量控制是用来优化或担保性能,改进延迟,和/或充实某些品种的多少包延迟满意某些标准下的可用带宽。假使某一个环节趋于饱和点,网络延迟可能大幅上升。因而,网络流量控制能够动用以预防这种景观时有暴发,并保障延迟性检查。

网络流量控制提供了一种手段来支配在指定时间内(带宽限制),被发送到网络中的数据量,或者是最大速率的多少流量发送。这种操纵可以兑现的门径有成百上千,但是日常状态下,网络流量控制总是采纳拖延发包来实现的,一般采取在网络边缘,以控制进入网络的流量,但也可平素采纳于数据源(例如,总计机或网卡),或是网络中的一个因素。

每便想到写一篇新的设计格局,我总会问自己:

流量监控限流算法

限流算法重要为:漏桶、令牌桶、计数器

1,自己领会了呢?

漏桶

一个永恒容量的漏桶,依照常量固定速率流出水滴。

图片 1 

 

2,我能以一种简单且有逻辑的章程把它说出去啊?

令牌桶

令牌桶算法是一个存放固定容量令牌的桶,依照固定速率往桶里添加令牌。

图片 2 

隐瞒做到万无一失,可是一本正经的放屁仍然要有吧,起码要忽悠得头头是道嘛(手动斜眼笑)

计数器

偶然我们还利用计数器来进展限流,首要用来限制总并发数,比如数据库连接池、线程池、秒杀的并发数;只要全局总请求数或者自然时间段的总请求数设定的阀值则展开限流,是简简单单粗暴的总数量限流,而不是平均速率限流。

至于工厂格局的多少个问题

限流措施

  • 限定总并发数(比如数据库连接池、线程池)
  • 界定刹那时并发数(如nginx的limit_conn模块,用来界定弹指时并发连接数)
  • 界定时间窗口内的平分速率(如Guava的RateLimiter、nginx的limit_req模块,限制每秒的平分速率)
  • 界定远程接口调用速率
  • 限定MQ的消费速率。
  • 可以遵照网络连接数、网络流量、CPU或内存负载等来限流

 

 

1,那一个是拿来干什么的?

行业

以下针对于国内相比较大型的互联网商家针对于流量监控架构方面的音讯征集

2,怎么用?

阿里

一向不找到相关的技巧资料,只是找到2016年分享的
“阿里管控系统靠什么样扛住大地最大范围的流量洪峰?”的文章,著作中关系了其不同境况采取的算法和限流框架。

用户洪峰

考虑的要素是:

a) 允许访问的速率

b) 系统接受的最大洪峰

c) 洪峰暴发的间隔时间

处理模式: 令牌桶限流

回调洪峰

除了0点0分的这种流量洪峰,还有系统里头的回调引起的大水。想象一下如此的气象,物流体系为了处理发货消息,会隔一段时间调用交易系统来获取交易新闻。为了提高效用,它每回批量询问交易系统的多寡。这样,对交易系统也带来了流量的撞击。即使对那种回调不加以限定,那么可能交易系统忙于处理这种回调洪峰,对用户洪峰会疏于处理。

对此这种洪峰,有两种特性:

a) 有距离频率

b) 每回调用量大

c) 允许有延期

处理模式:漏桶算法

限流框架分为:监控模块、决策模块、规则改变模块、限流模块。

图片 3 

 

3,不用可不可以?

腾讯

腾讯使用一种轻量级流控方案,方案如下:

1、计数器的key能“计时“

首先采纳接纳ckv作为计数器存储,相比较redis开发会更熟稔,同时怜惜也更便于,当然该方案也得以拔取redis作为计数器存储。

优势:方案用简短的艺术将全局流控服务做成原子化(计数和计时原子化),开发门槛低。

2、请求总结用拉取的方法替换上报

对于请求的总结办法,一般全量上报不可行,所有工作的请求量至少1:1禀报到ckv,ckv的容量和是个问题,单key也容易成为热门。定时仍然定量批量反馈,都没法儿担保实时流控,特别是请求量大的时候,流控延迟的题目会被加大。

优势:方案缩小ckv的访问量,同时保证流控的准头。

3、部署不需要agent

为了做更轻量的方案,我们考虑agent的必要性,分析发现,agent要形成的功能相比简单,重要职能托管到事情流控api。

优势:方案不应用agent的办法,部署维护更简短。

4、全局及单机流控同时启用

方案对容灾做了充足的考虑,重要解决方法是全局及单机流控同时启用,即基于ckv的大局流控和依照单机共享内存的单机流控都同时工作。

优势:方案有很好的容灾能力,容灾形式大概可行。

5、解决ckv性能瓶颈,流控性能达百万/s

出于选取ckv的incr以及配额拉取的落实格局,全局流控接入服务请求的能力赢得基金提升。

当前方案单独申请了一块ckv,容量为6G,使用incr的点子,压测性能达到9w+/s。

对事情空接口(Appplatform框架)做流控压测,使用30台v6虚拟机,单机50进程,压测性能达到50w+/s。

单接口50w/s的伏乞的劳务接通,同样也能满意多接口总体服务请求量50w+/s的全局流控需求。

上述的压测瓶颈首假如Appplatform框架的特性原因,由于拉取配额值是遵照流控阈值设定(一般>10),50w+的请求量只有不到5w的ckv访问量,ckv没到瓶颈。

优势:方案使用同一的资源(单独一块6G的ckv),能满足工作的请求量更高,性能达百万/s。

6、协理扩容和动态流控升级

辅助平行扩充流控能力,一套全局流控部署能满足流控的劳动请求量是达百万/s,更大的服务请求量需要安排多套全局流控。

匡助提高到动态流控能力,ckv写入的流控阈值是经过定时管理器完成,近日事情曾经做了健康度上报,定时管理器只需要对接健康度数据,分析接口当前哀告情况,动态调整流控阈值即可达成动态流控能力。

优势:方案总体简单轻量,扩容和提拔都很容易。

重中之重流程图

图片 4 

 

先是个和第四个问题,我现在就可以告诉您答案:早点收工,可以

京东

京东10亿调用量的高可用网关系统所涉及的技术栈:

接入层 Nginx+lua 技术。

NIO+Serviet3 异步技术。

分离技术。

降职限流。

熔断技术。

缓存,哪些地方该加缓存,哪些地方可以间接读库。

异构数据。

敏捷失败。

监察总计,这是一切高可用网关系统里特别关键的一有的。

有着的设计形式对我来说都是为了缩小工作量。关于缩小工作量我的精晓是:每个需求,都应有在它适合的时候出现适当的代码!这么些太重要了

小米

金立抢购限流峰值系统针对于一加商城秒杀抢购的兑现及技术架构

大秒系统的架构设计

图片 5 

 

大秒系统紧要由如下多少个模块组成

限流集群 HTTP 服务放号策略集群
Middle 服务监督数据核心 Dcacenter监控管理体系 Master准实时防刷模块
antiblack基础存储与日志队列服务: Redis 集群、Kafka 集群等

全套大秒系列中大秒前端模块
(HTTP/middle/antiblack) 和监察数据主导应用 golang
开发,大秒监控管理序列使用 Python + golang 开发。

大秒的前端架构设计

大秒前端的架构设计从四个系统举办

限流集群 HTTP 服务

策略集群 Middle 服务

准实时反作弊 antiblack 服务

图片 6 

 

代码偷懒,先前时期返工多

当当

遵照SOA架构理念,降低系统耦合性,接口定义清晰明确,保证独立子系统的健壮性高,降低故障跨系统扩散风险,从而将伸缩性的诸多不便逐渐分解到各类系统。

对系统举行个别,集中力量,突出重点系统。当当网从卖场到交易流程均属于一级系统,这有些序列一直关系用户体验和订单量。在系统稳定和可靠性等目的上,设计标准高于后台系统。

优先考虑用异步处理代替同步处理,做好系统充裕的降级方案,保证一定量的合格服务。

图片 7 

 

 

 

 

过火设计,中期返工多

方案

通过资料的采访,参考各大互联网集团的流量监控平台的架构搭建方案,大概通晓涉及的连串模块组成、限流算法、限流措施和规律。

归结各方资料整理得出简要的流量监控方案,流量监控可以分为多少个类别组合来形成其职责,这多少个平台首要的组成部分是:流量上报、限流、策略、调度。

设计格局+经验可以解决那一个题目,其他的自家还不知底。没有经历如何做?四个要点:

流量上报

重点用于采集系统的请求数据、状态和连串运行情况。有了这个运行数据,才能对外或对内举办表决处理;

1,能用

1、监控内容

1)对外和对外

对外用户请求

对内各种系统之间的回调请求

2)上报数据格式标准化

上报数据制定标准的

3)数据质地

4)实时和延时反映

5)硬件监控,如服务器的CPU、内存、网卡

6)心跳监控,时刻领悟每一个机器的运作情状

7)业务层监控,涉及JVM,Nginx的连接数

2,简洁

2、监控措施

1)、采用开源与shell脚本搭建监控平台

2)、自行研发监控平台

 

先是要达到能用,然后就是尽量简单,那样代码就不会太差。首先你要团结看得懂,然后是让队友看得懂。

限流 

重在是遵照流量上报的多少整合政策、调度来
举办对领先预想请求的处理形式,比如限流、排队等方法;

遵照不同情形拔取不同的限流算法,可以借鉴阿里针对于用户访问、物流、交易的处理格局。

1)用户访问:选拔令牌桶格局;

2)物流、交易:选择漏桶情势,平滑削峰处理;

3)购物车:采取分块网格化,单元处理

你了解你队友看到一堆烂的看都看不懂,也一句注释都并未的代码的时候的心绪阴影面积吗?

策略

要害是透过提前设置的体系、业务场景参数,来用于决定怎样境况用怎么着限流措施;相对的高风险的回应,也是政策的重要之处;在运动举行时,遵照监控上报的流量数据,动态灵活的调动政策也是相当紧要的;通过整治的材料提成一下策略方案:

1)水平扩充

针对不同服务器的压力举办增减服务器个数以促成劳务的下压力负载均衡,这样的话对于系统刚刚起始的伸缩性设计要求相比高,可以异常灵活的增长机器,来应对流量的变更。

2)系统分组

系统服务的事情不同,有优先级高的,有优先级低的,这就让不同的事体调用提前分组好的机械,那样的话在关键时刻,可以保基本业务。

3)业务降级

在一个用户请求,涉及到两个逻辑处理,其中不少可以没有的,可以在高并发的状态下,能够经过开关设置,来对非重点逻辑出来举办倒闭其请求,以提高了系统的主业务能力。

4)开关设置

对此每一个体系业务请求,都增减相应的开关设置,可以实时应对高并发情况下,依据气象实现动态调度的法力。

 

这实质上也没怎么,什么人没填过旁人的坑呢?关键是她知道你家在何地,而且还精通您日常走夜路,就问你怕不怕?(卧槽,又跑题了。。)

调度

提供给领导相应的调度数据,实时展现系统运转境况,并在领导下达仲裁指令后急速执行政策;如何来兑现大概的方案如下:

1、建立基本数据可视化平台

2、策略规则可以动态配置

3、各类业务线开关集中管理

4、自动化的台本执行

5、运维服务的动态化管理

6、命令执行的散发协议和同步管理

 

总结

流量监控为电商平台提供高速稳定的运作环境的基础,它是无时不刻的督查整个平台的周转情形、并为决策者提供实时数据以供参考;流量监控平毕尔巴鄂的限流只是一种保护体制,咋样承接高并发、大流量的用户请求,如故需要与另外平台合作,以高达给用户最好的用户体验。

 

 

 

 

急需:你有一个披萨店,只卖一种披萨,代码如下:

参考自著作

腾讯轻量级全局流控方案详解

http://wetest.qq.com/lab/view/320.html?from=content\_toutiao&hmsr=toutiao.io&utm\_medium=toutiao.io&utm\_source=toutiao.io

当当网系统分级与海量信息动态宣布进行

http://www.csdn.net/article/2014-11-07/2822541

披萨:

华为抢购限流峰值系统「大秒」架构解密

https://mp.weixin.qq.com/s?\_\_biz=MzAwMDU1MTE1OQ==&mid=402182304&idx=1&sn=1bd68d72e6676ff782e92b0df8b07d35&scene=1&srcid=12045k1zDgO7DLlMLwimBKjC&from=groupmessage&isappinstalled=0\#wechat\_redirect

import java.util.ArrayList;
import java.util.List;

/**
 * 披萨类
 * @author skysea
 */
public class Pizza {

    private String name;//披萨名称

    private String dough;//面团

    private String sauce;//酱料

    private List<String> toppings = new ArrayList<>();//佐料

    public Pizza() {
            this.name = "原味披萨";
            this.dough = "原味面团";
            this.sauce = "原味酱料";
    }

    void prepare() {
        System.out.println("开始准备披萨:" + name);

        System.out.println("开始处理面团:" + dough);

        System.out.println("添加酱料:" + sauce);

        System.out.println("添加佐料:");
        if(toppings.size() > 0) {
            for(String t : toppings) {
                System.out.println(" " + t);
            }
        }
    }

    void bake() {
        System.out.println("烘焙25分钟..");
    }

    void cut() {
        System.out.println("披萨切片..");
    }

    void box() {
        System.out.println("披萨打包..");
    }

    public String getName() {
        return name;
    }
}

阿里管控系统靠什么扛住大地最大局面的流量洪峰?

http://jm.taobao.org/2016/05/19/how-to-withstand-the-world-s-largest-traffic/?hmsr=toutiao.io&utm\_medium=toutiao.io&utm\_source=toutiao.io

 

披萨店:

/**
 * 只卖一种披萨的披萨店
 * @author skysea
 */
public class PizzaStore {

    public Pizza orderPizza() {
        Pizza pizza = new Pizza();
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

 测试类:

/**
 * pizza测试类
 * @author skysea
 */
public class PizzaTest {
    public static void main(String[] args) {
        PizzaStore pizzaStore = new PizzaStore();
        Pizza pizza = pizzaStore.orderPizza();
        System.out.println("当前预定的披萨:" + pizza.getName());
    }
}

图片 8 

今昔披萨店要拓展工作了,因为卖一种披萨顾客曾经吃腻了,现在要起来添加新的披萨类型

简简单单工厂情势

Pizza类的立异

import java.util.ArrayList;
import java.util.List;

/**
 * 披萨抽象类
 * 1,修改private -> protected(保证子类拥有这些属性)
 * 2,将Pizza定义为abstract类,防止被new,也是为后面的改造做准备
 * @author skysea
 */
public abstract class Pizza {

    protected String name;//披萨名称

    protected String dough;//面团

    protected String sauce;//酱料

    protected List<String> toppings = new ArrayList<>();//佐料

    void prepare() {
        System.out.println("开始准备披萨:" + name);

        System.out.print("开始处理面团:" + dough);

        System.out.println("添加酱料:" + sauce);

        System.out.println("添加佐料:");
        for(String t : toppings) {
            System.out.println(" " + t);
        }
    }

    void bake() {
        System.out.println("烘焙25分钟..");
    }

    void cut() {
        System.out.println("披萨切片..");
    }

    void box() {
        System.out.println("披萨打包..");
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Pizza [name=" + name + ", dough=" + dough + ", sauce=" + sauce + ", toppings=" + toppings + "]";
    }
}

先付给新增的披萨

芝士披萨:

图片 9图片 10

/**
 * 芝士披萨
 * @author skysea
 */
public class CheesePizza extends Pizza{
    public CheesePizza() {
        this.name = "芝士披萨";
        this.dough = "芝士披萨的面团";
        this.sauce = "芝士披萨的酱料";
        this.toppings.add("很多芝士....");
    }
}

View Code

蛤蜊披萨:

图片 11图片 12

/**
 * 蛤蜊披萨
 * @author skysea
 */
public class ClamPizza extends Pizza {
    public ClamPizza() {
        this.name = "蛤蜊披萨";
        this.dough = "蛤蜊披萨的面团";
        this.sauce = "蛤蜊披萨的酱料";
        this.toppings.add("蛤蜊");
    }
}

View Code

意大利烤肠披萨:

图片 13图片 14

/**
 * 意大利烤肠披萨
 * @author skysea
 */
public class PepperoniPizza extends Pizza{

    public PepperoniPizza() {
        this.name = "意大利烤肠披萨";
        this.dough = "意大利烤肠披萨的面团";
        this.sauce = "意大利烤肠披萨的酱料";
        this.toppings.add("一大波意大利烤肠...");
    }
}

View Code

 素食比萨:

图片 15图片 16

/**
 * 素食比萨
 * @author skysea
 */
public class VeggiePizza extends Pizza {
    public VeggiePizza() {
        name = "素食比萨";
        dough = "素食比萨的面团";
        sauce = "素食比萨的酱料";
        toppings.add("素食比萨");
        toppings.add("素食比萨佐料1");
        toppings.add("素食比萨佐料2");
    }
}

View Code

贴了如此多代码,先提交一波简单的落实:

/**
 * pizza店
 * @author skysea
 */
public class PizzaStore {

    public Pizza orderPizza(String type) {
        Pizza pizza = null;
        if (type.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (type.equals("pepperoni")) {
            pizza = new PepperoniPizza();
        } else if (type.equals("clam")) {
            pizza = new ClamPizza();
        } else if (type.equals("veggie")) {
            pizza = new VeggiePizza();
        }

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

}

在不考虑继续扩大披萨系列的时候,这样的落实有没有问题,一般的话,达到了可以用的正儿八经,不过不佳用,问题如下:

1,没有兼容原来的一种披萨方法 public Pizza
orderPizza(),相信自己,每一个public方法都是很重大的,因为您不知晓有稍许地点用到过。当然也不是没办法知道,只是你通晓也不自然就能改,虽然你能改,也不肯定改对。

2,String类型的type太容易失误了,个人感觉对程序支付不自己,当然那个也要分情状,灵活和谨慎本来就很难完成两全

3,推荐取不到适当的type时抛相当,而不是回来空,便于排查问题(此处的if里面只是一贯new重临的靶子,实际情况远比现在的错综复杂)

交由第二版:

/**
 * pizza店
 * @author skysea
 */
public class PizzaStore {

    public Pizza orderPizza() {
        return orderPizza(PizzaTypeEnum.CHEESE);
    }

    public Pizza orderPizza(PizzaTypeEnum type) {
        Pizza pizza;

        pizza = SimplePizzaFactory.getPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

SimplePizzaFactory:

/**
 * 简单工厂类
 * @author skysea
 */
public class SimplePizzaFactory {

    /**
     * 根据类型获取pizza
     * @param type
     * @return
     */
    public static final Pizza getPizza(PizzaTypeEnum type){
        switch (type) {
            case CHEESE: return new CheesePizza();
            case CLAM: return new ClamPizza();
            case PEPPERONI: return new PepperoniPizza();
            case VEGGIE: return new VeggiePizza();
            default: throw new NoSuchPizzaException(type.getCode());
        }
    }
}

辅助类(枚举,异常):

图片 17图片 18

/**
 * 定义pizza类型枚举
 * @author skysea
 *
 */
public enum PizzaTypeEnum{
    /**
     * 芝士披萨
     */
    CHEESE("cheese"),
    /**
     * 意大利烤肠披萨
     */
    PEPPERONI("pepperoni"),
    /**
     * 蛤蜊披萨
     */
    CLAM("clam"),
    /**
     * 素食比萨
     */
    VEGGIE("veggie");
    private final String code;
    PizzaTypeEnum(String code) {
        this.code = code;
    }
    public String getCode() {
        return code;
    }
}

View Code

图片 19图片 20

/**
 * 没有匹配的pizza异常
 * @author skysea
 */
public class NoSuchPizzaException extends RuntimeException{
    private static final long serialVersionUID = 6831396172306375611L;
    public NoSuchPizzaException(String message) {
        super(message);
    }
}

View Code

测试类:

/**
 * pizza测试类
 * @author skysea
 */
public class PizzaTest {

    public static void main(String[] args) {
        PizzaStore store = new PizzaStore();

        Pizza pizza = store.orderPizza(PizzaTypeEnum.CHEESE);
        System.out.println(pizza);

        pizza = store.orderPizza(PizzaTypeEnum.VEGGIE);
        System.out.println(pizza);
    }
}

图片 21

好了,代码写到这里,其实对于:新增披萨类型的这些需求的贯彻其实早已很好了。至少来说现阶段的急需实现了,其次就是对调用方友好,至少队友不会跑过来问您类型传啥,不会告知您他string字符串传错了,不会在你改个品类的时候,还要布告他(当然这多少个也得以通过常量来拍卖)。

吹了半天,来说说那段代码的题目,正常情形下,需求会是这样变:

1,PepperoniPizza暂时不要了,一般的话,你问她要不要,他会说,那些要看前面的运营情况(我:…)

2,你给自身新加一个xx披萨

前几天急需改的是五个位置,一个是工厂类,一个是枚举,不过根本的流水线是永不改了,假若你以为如故很费力在不考虑性能的气象下,你还能用反射来玩,改造一下厂子类(实现通过class来创制对象)和枚举(添加一个字段来存放type对应的class)就足以了,不赘述..

第一波需求就基本上可以这么收手了,随着事情的发展,披萨店这叫一个富裕啊,即使中间也对代码做了累累新的披萨,可是由于PizzaStore非常稳定,也没出什么大题目。

新的题材(开分店):

1,旗舰店在首尔,现在要在伦敦开一家新的店

2,分店的披萨口味要基于地点的口味来拓展调整,保证可以不失品牌特色的还要,也能满意当地特有的韵味

3,分店披萨的门类与暂时与旗舰店保持一致

厂子方法形式

先把具有的披萨列出来

吉隆坡的披萨:

图片 22图片 23

/**
 * 芝加哥芝士披萨
 * @author skysea
 */
public class ChicagoStyleCheesePizza extends Pizza {

    public ChicagoStyleCheesePizza() { 
        name = "芝加哥芝士披萨";
        dough = "芝加哥芝士披萨面团";
        sauce = "芝加哥芝士披萨酱料";

        toppings.add("芝加哥芝士披萨调料1");
        toppings.add("芝加哥芝士披萨调料2");
    }

    @Override
    void cut() {
        System.out.println("芝加哥芝士披萨版切片...");
    }
}
/**
 * 芝加哥蛤蜊披萨
 * @author skysea
 */
public class ChicagoStyleClamPizza extends Pizza {
    public ChicagoStyleClamPizza() {
        name = "芝加哥蛤蜊披萨";
        dough = "芝加哥蛤蜊披萨面团";
        sauce = "芝加哥蛤蜊披萨酱料";

        toppings.add("芝加哥蛤蜊披萨佐料1");
        toppings.add("芝加哥蛤蜊披萨佐料2");
    }

    @Override
    void cut() {
        System.out.println("芝加哥蛤蜊披萨版切片...");
    }
}
/**
 * 芝加哥意大利烤肠披萨
 * @author skysea
 */
public class ChicagoStylePepperoniPizza extends Pizza {
    public ChicagoStylePepperoniPizza() {
        name = "芝加哥意大利烤肠披萨";
        dough = "芝加哥意大利烤肠披萨面团";
        sauce = "芝加哥意大利烤肠披萨酱料";

        toppings.add("芝加哥意大利烤肠披萨调料1");
        toppings.add("芝加哥意大利烤肠披萨调料2");
        toppings.add("芝加哥意大利烤肠披萨调料3");
        toppings.add("芝加哥意大利烤肠披萨调料4");
    }

    @Override
    void cut() {
        System.out.println("芝加哥意大利烤肠披萨版切片...");
    }
}
/**
 * 芝加哥素食比萨
 * @author skysea
 */
public class ChicagoStyleVeggiePizza extends Pizza {
    public ChicagoStyleVeggiePizza() {
        name = "芝加哥素食比萨";
        dough = "芝加哥素食比萨的面团";
        sauce = "芝加哥素食比萨的酱料";

        toppings.add("芝加哥素食比萨调料1");
        toppings.add("芝加哥素食比萨调料2");
        toppings.add("芝加哥素食比萨调料3");
    }

    void cut() {
        System.out.println("芝加哥素食比萨版切片...");
    }
}

View Code

伦敦的披萨:

图片 24图片 25

/**
 * 纽约芝士披萨
 * @author skysea
 */
public class NYStyleCheesePizza extends Pizza {

    public NYStyleCheesePizza() { 
        name = "纽约芝士披萨";
        dough = "纽约芝士披萨面团";
        sauce = "纽约芝士披萨酱料";

        toppings.add("纽约芝士披萨调料1");
        toppings.add("纽约芝士披萨调料2");
    }

    @Override
    void cut() {
        System.out.println("纽约芝士披萨版切片...");
    }
}
/**
 * 纽约蛤蜊披萨
 * @author skysea
 */
public class NYStyleClamPizza extends Pizza {
    public NYStyleClamPizza() {
        name = "纽约蛤蜊披萨";
        dough = "纽约蛤蜊披萨面团";
        sauce = "纽约蛤蜊披萨酱料";

        toppings.add("纽约蛤蜊披萨佐料1");
        toppings.add("纽约蛤蜊披萨佐料2");
    }

    @Override
    void cut() {
        System.out.println("纽约蛤蜊披萨版切片...");
    }
}
/**
 * 纽约意大利烤肠披萨
 * @author skysea
 */
public class NYStylePepperoniPizza extends Pizza {
    public NYStylePepperoniPizza() {
        name = "纽约意大利烤肠披萨";
        dough = "纽约意大利烤肠披萨面团";
        sauce = "纽约意大利烤肠披萨酱料";

        toppings.add("纽约意大利烤肠披萨调料1");
        toppings.add("纽约意大利烤肠披萨调料2");
        toppings.add("纽约意大利烤肠披萨调料3");
        toppings.add("纽约意大利烤肠披萨调料4");
    }

    @Override
    void cut() {
        System.out.println("纽约意大利烤肠披萨版切片...");
    }
}
/**
 * 纽约素食比萨
 * @author skysea
 */
public class NYStyleVeggiePizza extends Pizza {
    public NYStyleVeggiePizza() {
        name = "纽约素食比萨";
        dough = "纽约素食比萨的面团";
        sauce = "纽约素食比萨的酱料";

        toppings.add("纽约素食比萨调料1");
        toppings.add("纽约素食比萨调料2");
        toppings.add("纽约素食比萨调料3");
    }

    void cut() {
        System.out.println("纽约素食比萨版切片...");
    }
}

View Code

披萨倒是列完了,但是在其实的支付过程中,业务逻辑这么简单这是不能的,想要改那怎么旗舰店披萨的类名是很劳顿的

一般要考虑:

1,是不是单机,有没有其他外部系统在调用

2,改动原来的代码有如何利益,更易于了解吧?迭代了多少个本子之后垃圾代码太多了呢?

3,影响大不大

本来,我这边是随便造,你们啊,我就不领悟了,嘿嘿嘿,所以境遇这种情状,一般的话要悠着点,看日子,也要看影响,开发就是如此,同一个效能,2天有2天的做法,5天有5天的做法,10天有10天的做法

披萨店改造:

/**
 * 披萨店抽象类
 * @author skysea
 */
public abstract class PizzaStore {

    abstract Pizza createPizza(String item);

    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        System.out.println("--- 制作 " + pizza.getName() + " ---");
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

/**
 * 芝加哥披萨店
 * @author skysea
 */
public class ChicagoPizzaStore extends PizzaStore {
    public static final String CHEESE = "cheese";
    public static final String VEGGIE = "veggie";
    public static final String CLAM = "clam";
    public static final String PEPPERONI = "pepperoni";
    Pizza createPizza(String item) {
        if (CHEESE.equals(item)) {
            return new ChicagoStyleCheesePizza();
        } else if (VEGGIE.equals(item)) {
            return new ChicagoStyleVeggiePizza();
        } else if (CLAM.equals(item)) {
            return new ChicagoStyleClamPizza();
        } else if (PEPPERONI.equals(item)) {
            return new ChicagoStylePepperoniPizza();
        } else {
            throw new NoSuchPizzaException(item);
        }
    }
}

伦敦披萨店(和莫斯科披萨店几乎一毛一样,这里就不举办了):

图片 26图片 27

/**
 * 纽约披萨店
 * @author skysea
 */
public class NYPizzaStore extends PizzaStore {

    public static final String CHEESE = "cheese";
    public static final String VEGGIE = "veggie";
    public static final String CLAM = "clam";
    public static final String PEPPERONI = "pepperoni";
    Pizza createPizza(String item) {
        if (CHEESE.equals(item)) {
            return new NYStyleCheesePizza();
        } else if (VEGGIE.equals(item)) {
            return new NYStyleVeggiePizza();
        } else if (CLAM.equals(item)) {
            return new NYStyleClamPizza();
        } else if (PEPPERONI.equals(item)) {
            return new NYStylePepperoniPizza();
        } else {
            throw new NoSuchPizzaException(item);
        }
    }
}

View Code

这段代码有多少个问题要精晓精晓:

1,那么些地点为啥要弄个抽象类出来?

以此即将结合实际来了然了,分店与分店之间,需不需要统一规范化管理?需不需要保证自己的特征?答案肯定,都是索要的

其一地点创建披萨的进程,毫无疑问是毫无疑问要平等的。就像外卖一样,下单,炒菜,配送。整套流程都是这样,不可能说你出去就起来炒菜了哟,这不科学。不一样的地方就是,你炒的如何菜,好不佳吃。配送得快不快,稳不稳,服务好不好。

就此,抽象类的意义就是:规范、特色

2,factory咋个不见了?

因为把它和实际的store合并在共同了,这样又引申出此外一个题目:为何要联合?因为store现在充当的角色就是facotry,刚才说过的打造过程已经松开父类中贯彻了,现在只需要在切实可行的store中去化解披萨的创导问题

3,为什么又毫无枚举了,弄个String来创立pizza?

只要仍然单机,用枚举当然会比一贯扔个string来得服服帖帖。

开了分公司,假设每个子公司都是一套完整的劳务在玩,丢个string,要比枚举来得好。原因有2:传输过程中的连串化和反连串化、更加灵敏(客户端不用每一回都因为这么些原因要去提高对应的包,特别是五个本子在跑得时候,升级了又会促成其他东西不可能玩)

测试类:

/**
 * 披萨测试类
 * @author skysea
 */
public class PizzaTest {

    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();

        Pizza pizza = nyStore.orderPizza(NYPizzaStore.CHEESE);
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");

        pizza = chicagoStore.orderPizza(ChicagoPizzaStore.CHEESE);
        System.out.println("Joel ordered a " + pizza.getName() + "\n");

        pizza = nyStore.orderPizza(NYPizzaStore.CLAM);
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");

        pizza = chicagoStore.orderPizza(ChicagoPizzaStore.CLAM);
        System.out.println("Joel ordered a " + pizza.getName() + "\n");

        pizza = nyStore.orderPizza(NYPizzaStore.PEPPERONI);
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");

        pizza = chicagoStore.orderPizza(ChicagoPizzaStore.PEPPERONI);
        System.out.println("Joel ordered a " + pizza.getName() + "\n");

        pizza = nyStore.orderPizza(NYPizzaStore.VEGGIE);
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");

        pizza = chicagoStore.orderPizza(ChicagoPizzaStore.VEGGIE);
        System.out.println("Joel ordered a " + pizza.getName() + "\n");
    }
}

结果(结果太多了,就不全体截图出来了):

图片 28

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注