headfirst设计模式(4)—工厂模式

时间:2019-12-23 06:51来源:永利皇宫手机版网址
开篇 时刻逛乐乎,就是狠不下心来写篇博客,忙是豆蔻梢头派,然而说忙能有多忙啊,皆不常光逛微博,写篇博客的岁月都尚未?(那还真不佳说) 老是想到写意气风发篇新的设计形

开篇

时刻逛乐乎,就是狠不下心来写篇博客,忙是豆蔻梢头派,然而说忙能有多忙啊,皆不常光逛微博,写篇博客的岁月都尚未?(那还真不佳说)

老是想到写意气风发篇新的设计形式,小编总会问自身:

1,自个儿通晓了啊?

2,作者能以风华正茂种轻松且有逻辑的方法把它说出去啊?

背着做到百下百全,不过一本正经的放屁如故要有吗,起码要忽悠得井井有条嘛(手动斜眼笑)

关于工厂方式的多少个难题

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

2,怎么用?

3,不用可以还是不可以?

headfirst设计模式(4)—工厂模式。headfirst设计模式(4)—工厂模式。先是个和第八个难点,作者现在就能够告诉你答案:早点收工,能够

不无的设计格局对本人来讲皆感到了收缩工作量。关于裁减专门的学业量笔者的知情是:各样供给,都应当在它适用的时候现身适当的代码!那么些太首要了

代码偷懒,中期返工多

headfirst设计模式(4)—工厂模式。过度设计,早先时期返工多

设计方式+阅历得以缓和这么些难题,别的的小编还不知晓。未有阅历如何是好?五个核心:

1,能用

2,简洁

第少年老成要达到规定的典型能用,然后正是尽或许简洁明了,那样代码就不会太差。首先你要协和看得懂,然后是让队友看得懂。

你知道您队友看见一批烂的看都看不懂,也一句注释都还未的代码的时候的思维阴影面积吗?

那实在也没怎么,哪个人没填过别人的坑呢?关键是她精通你家在哪个地方,并且还通晓您时常走夜路,就问你怕不怕?(卧槽,又跑题了。。)

 

要求:你有二个披萨店,只卖后生可畏种披萨,代码如下:

披萨:

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;
    }
}

 

披萨店:

/**
 * 只卖一种披萨的披萨店
 * @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());
    }
}

图片 1 

近来披萨店要开展工作了,因为卖生机勃勃种披萨客户曾经吃腻了,现在要从头加多新的披萨类型

headfirst设计模式(4)—工厂模式。简单的讲工厂方式

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 + "]";
    }
}

先交给新扩充的披萨

芝士披萨:

图片 2图片 3

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

View Code

蛤蜊披萨:

图片 4图片 5

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

View Code

意国烤肠披萨:

图片 6图片 7

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

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

View Code

 素食比萨:

图片 8图片 9

/**
 * 素食比萨
 * @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());
        }
    }
}

辅助类(枚举,异常):

图片 10图片 11

/**
 * 定义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

图片 12图片 13

/**
 * 没有匹配的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);
    }
}

图片 14

好了,代码写到这里,其实对于:新扩充披萨类型的那一个需要的贯彻其实早就很好了。最少来讲现阶段的急需完毕了,其次正是对调用方友好,起码队友不会跑过来问你类型传啥,不会告知您他string字符串传错了,不会在你改个品类的时候,还要通告他(当然这一个也可以因此常量来拍卖)。

吹了半天,来讲说这段代码的题材,寻常情况下,须要会是这么变:

1,PepperoniPizza一时不要了,日常的话,你问她要不要,他会说,这些要看前边的运维景况(小编:...)

2,你给笔者新加叁个xx披萨

今昔要求改的是多少个地点,二个是工厂类,二个是枚举,可是根本的流程是却非改了,要是你认为依旧很辛勤在不思谋质量的气象下,你还能用反射来玩,退换一下工厂类(完成通过class来创设对象卡塔尔国和枚举(加多二个字段来寄放type对应的class)就能够了,不赘述..

首先波须求就比很多能够那样收手了,随着业务的迈入,披萨店那叫二个富厚啊,纵然中间也对代码做了过多新的披萨,然而出于PizzaStore格外稳定,也没出什么大标题。

新的标题(开分店):

1,连锁店在首尔,现在要在London开一家新的店

2,分店的披萨口味要基于地点的口味来进展调度,保障能够不失品牌特色的还要,也能满意本地独特的韵味

3,分店披萨的门类与临时与专营店保持少年老成致

工厂方法格局

先把具备的披萨列出来

洛杉矶的披萨:

图片 15图片 16

/**
 * 芝加哥芝士披萨
 * @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

London的披萨:

图片 17图片 18

/**
 * 纽约芝士披萨
 * @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);
        }
    }
}

London披萨店(和法兰克福披萨店大致一毛同样,这里就不开展了):

图片 19图片 20

/**
 * 纽约披萨店
 * @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");
    }
}

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

图片 21

 

 

编辑:永利皇宫手机版网址 本文来源:headfirst设计模式(4)—工厂模式

关键词: