美文网首页Android知识
工厂模式:摄计魔士和他的炼丹密室

工厂模式:摄计魔士和他的炼丹密室

作者: 離枝 | 来源:发表于2017-03-01 14:48 被阅读0次

    从前有一座山叫爪娲山,山峰上住着一个神龙见首不见尾的道士,江湖上的外号叫摄计魔士,他在密室里放着一座炼丹炉。(抱着娱乐的精神,类名方法名有一些用了中文命名,不规范。在Head First Design Pattern这本书里面,举了一个Pizza店的例子,我觉得很不错。我想了如下这个不同的例子,来说明同样的问题。)本文系原创<br />

    为什么需要工厂模式?使用工厂模式有什么好处?可以解决什么问题?

    炼丹第一重境界:
    摄计魔士刚入行时,涉世不深,只会炼一种丹,所以炼丹的代码比较简陋

    public class 丹 {
        public static 丹 makeDan() {
            丹 dan = new 丹();
            dan.准备();
            dan.炼制();
            dan.收工();
            return dan;
        }
    
        private void 收工() {
            System.out.println("七七四十九天,九九八十一轮回,神丹已成,请您享用");
        }
    
        private void 炼制() {
            System.out.println("麻利麻利哄,炼制过程开始。。。");
        }
    
        private void 准备() {
            System.out.println("准备开始炼丹");
        }
    }
    

    测试丹.makeDan();,运行结果如下


    炼丹第二重境界:(静态工厂方法)
    随着炼丹水平的提升,摄计魔士学会了用不同的元素炼丹
    丹.class
    public class 丹 {
        static 丹 makeDan(String element) {
            丹 dan = null;
            if (element.equals("金")) {
                dan = new 金丹();
            } else if (element.equals("银")) {
                dan = new 银丹();
            } else if (element.equals("铜")) {
                dan = new 铜丹();
            } else if (element.equals("宋丹")) {
                dan = new 宋丹丹();
            }
            if (dan != null) {
                dan.准备();
                dan.炼制();
                dan.收工(element);
            }
            return dan;
        }
    
        public void 收工(String element) {
            System.out.println("七七四十九天,九九八十一轮回," + element + "丹已成,请您享用\n");
        }
    
        public void 炼制() {
            System.out.println("麻利麻利哄,炼制过程开始。。。");
        }
    
        public void 准备() {
            System.out.println("准备开始炼丹");
        }
    }
    

    DanTestDrive.class

    public class DanTestDrive {
        public static void main(String[] args) {
            丹.makeDan("金");
            丹.makeDan("宋丹");
        }
    }
    

    运行结果:


    炼丹第三重境界:(简单工厂)
    丹.class
    interface 丹 {
        public void 收工();
    
        public void 炼制();
    
        public void 准备();
    }
    
    

    金丹.class

    public class 金丹 implements 丹 {
        @Override
        public void 收工() {
            System.out.println("炼制完成,用上等的鎏金兽牙盒包装\n");
        }
    
        @Override
        public void 炼制() {
            System.out.println("金丹炼制中...");
        }
    
        @Override
        public void 准备() {
            System.out.println("加入黄金二两,秘方若干两");
        }
    }
    
    

    银丹.class

    public class 银丹 implements 丹 {
        @Override
        public void 收工() {
            System.out.println("炼制完成,用陈年黑檀木盒包装\n");
        }
    
        @Override
        public void 炼制() {
            System.out.println("银丹炼制中....");
        }
    
        @Override
        public void 准备() {
            System.out.println("加入白银二两,秘方若干两");
        }
    }
    

    炼丹密室.class

    public class 炼丹密室 {
        简丹工厂 factory;
    
        public 炼丹密室(简丹工厂 factory) {
            this.factory = factory;
        }
    
        public 丹 makeDan(String element) {
            丹 dan;
            dan = factory.createDan(element);
            dan.准备();
            dan.炼制();
            dan.收工();
            return dan;
        }
    }
    

    简丹工厂.class

    public class 简丹工厂 {
        丹 createDan(String element) {
            丹 dan = null;
            if (element.equals("金")) {
                dan = new 金丹();
            } else if (element.equals("银")) {
                dan = new 银丹();
            } else if (element.equals("铜")) {
                dan = new 铜丹();
            } else if (element.equals("宋丹")) {
                dan = new 宋丹丹();
            }
            return dan;
        }
    }
    

    测试类

    public class DanTestDrive {
        public static void main(String[] args) {
            炼丹密室 炼丹密室 = new 炼丹密室(new 简丹工厂());
            炼丹密室.makeDan("金");
            炼丹密室.makeDan("银");
        }
    }
    
    

    运行结果:

    结构图:


    炼丹第四重境界1:(工厂模式)
    摄计魔士带的几个徒弟都出师了,他们是思聪、御凤、强东、芙蓉四大炼丹术士,虽然师出同门,但他们每个人炼丹都有自己的风格,原来一间小小的炼丹密室已经不够用了。<br />
    原先是在炼丹密室的构造函数中,传入简丹工厂的引用,然后在炼丹密室的makeDan方法中,调用简丹工厂中的createDan()(dan = factory.createDan(element);),以得到不同种类的丹,现在因为徒弟出师了,师父必须在更高的层次上来设计炼丹的标准。createDan从简丹工厂中移到炼丹密室中,并使之成为抽象方法,从而炼丹密室成为一个抽象类<br />
    在此例中可见,“炼丹密室”这个类运用了工厂方法模式,它定义了一个创建对象的接口(createDan),具体要实例化的类(丹类)是哪一个,是由继承“炼丹密室”的子类所决定的。工厂方法让类的实例化推迟到子类中。这样,在炼丹密室这个父类中,所做的是制定流程的事,把不变的部分放在其中,比如将丹类的三个方法按顺序排好,丹需要先准备、然后炼制,最后收工。但是具体的实现过程,因丹而异(比如强东的金丹,他要放入狗粮和奶茶粉的配料)。不能将变动的内容放入到炼丹密室中,每种具体的实现,都由每种不同的丹的子类去实现。

    炼丹密室.class

    public abstract class 炼丹密室 {
        public 丹 makeDan(String element) {
            丹 dan;
            dan = createDan(element);
            dan.准备();
            dan.炼制();
            dan.收工();
            return dan;
        }
    
        protected abstract 丹 createDan(String element);
    }
    

    思聪的炼丹密室.class

    public class 思聪的炼丹密室 extends 炼丹密室 {
        @Override
        protected 丹 createDan(String element) {
            if (element.equals("金")) {
                return new 思聪的秘制金丹();
            } else if (element.equals("银")) {
                return new 思聪的秘制银丹();
            } else {
                return null;
            }
        }
    }
    

    思聪的秘制银丹.class

    public class 思聪的秘制银丹 implements 丹 {
        @Override
        public void 收工() {
            System.out.println("银丹炼制完成,用明成化斗彩鸡缸杯来装\n");
        }
    
        @Override
        public void 炼制() {
            System.out.println("银丹炼制中...");
        }
    
        @Override
        public void 准备() {
            System.out.println("思聪秘制银丹炼制准备。。。");
            System.out.println("放入银两,再加两斤钻石磨成粉");
        }
    }
    

    强东的炼丹密室.class

    public class 强东的炼丹密室 extends 炼丹密室 {
        @Override
        protected 丹 createDan(String element) {
            if (element.equals("金")) {
                return new 强东的秘制金丹();
            } else if (element.equals("银")) {
                return new 强东的秘制银丹();
            } else {
                return null;
            }
        }
    }
    

    强东的秘制金丹.class

    public class 强东的秘制金丹 implements 丹 {
        @Override
        public void 收工() {
            System.out.println("用上等的塑料袋包装\n");
        }
    
        @Override
        public void 炼制() {
            System.out.println("金丹炼制中,等6月18日来拿...");
        }
    
        @Override
        public void 准备() {
            System.out.println("强东的金丹铺子开张啦。。。");
            System.out.println("金丹准备,加一点点奶茶粉");
        }
    }
    

    测试类

    public class DanTestDrive {
        public static void main(String[] args) {
            炼丹密室 sicongRoom = new 思聪的炼丹密室();
            sicongRoom.makeDan("银");
            炼丹密室 qiangdongRoom = new 强东的炼丹密室();
            qiangdongRoom.makeDan("金");
        }
    }
    

    输出结果:


    炼丹第四重境界2:(工厂模式)
    师父一看徒弟们炼的丹,完全随心所欲,他决定在质量上面增加一点点把控,于是他做了一些改变,首先就是把原先“丹”由接口变成抽象类
    丹.class
    public abstract class 丹 {
        String name;
        String roomName;
        String creatorName;
        String packageName;
        List<String> additions = new ArrayList<String>();
    
        public String getName() {
            return name;
        }
    
        public void 收工() {
            System.out.println("炼制完成," + name + "将由" + packageName + "包装\n");
        }
    
        public void 炼制() {
            System.out.println(name + "正在炼制中。。。");
        }
    
        public void 准备() {
            System.out.println("爪娲山炼丹密室之" + roomName + "开始炼丹。。。");
            System.out.println("接下来将由" + creatorName + "大师开始炼制" + name);
            System.out.println("架炉生火");
            System.out.println("接下来放入" + roomName + "的秘制配方:");
    
            for (int i = 0; i < additions.size(); i++) {
                System.out.println("  " + (i+1) + ":" + additions.get(i));
            }
        }
    }
    

    强东的秘制银丹.class

    public class 强东的秘制银丹 extends 丹 {
        public 强东的秘制银丹() {
            name = "强东的秘制银丹";
            roomName = "强东的炼丹密室";
            creatorName = "强东";
            packageName = "塑料袋";
            additions.add("奶茶粉");
            additions.add("狗粮");
        }
    }
    
    

    思聪的秘制银丹.class

    public class 思聪的秘制银丹 extends 丹 {
        public 思聪的秘制银丹() {
            name = "思聪的秘制银丹";
            roomName = "思聪的炼丹密室";
            creatorName = "思聪";
            packageName = "斗彩鸡缸杯";
            additions.add("钻石粉");
            additions.add("一打iphone");
            additions.add("陨石");
        }
    }
    

    测试类

    public class DanTestDrive {
        public static void main(String[] args) {
            炼丹密室 sicongRoom = new 思聪的炼丹密室();
            sicongRoom.makeDan("银");
            炼丹密室 qiangdongRoom = new 强东的炼丹密室();
            qiangdongRoom.makeDan("银");
        }
    }
    

    输出结果:

    结构图



    炼丹第五重境界:(抽象工厂模式)
    一山不容二虎,徒儿们渐渐翅膀长硬了,于是都想着要各奔东西了。原本炼丹,第一味总是要先加入师父提供的秘方,才能够炼制成功。不管是金丹还是银丹,都需要加入它,这味秘方被称为“丹魂”(不是混蛋),即丹的灵魂的意思。摄计魔士知道徒儿们的心思,于是意味深长地和徒儿们道出了秘方:丹魂是由三种东西构成的:清晨的露水,白色的羽毛以及若干种兽骨,唯有丹魂,才有神丹。金丹的丹魂是清晨的露水、白色的羽毛及若干种兽骨 ,银丹的丹魂是清晨的露水和白色的羽毛,铜丹的丹魂只需要清晨的露水。

    金丹 银丹 铜丹
    清晨的露水
    白色的羽毛 <br />
    若干种兽骨 <br /> <br />

    其中御凤去了亚美利加大洲,她炼制金丹时,用了美洲雕的羽毛,清晨中央公园嫩叶上的露水以及火鸡骨和北美的野牛骨作为丹魂。而思聪则留在了大陆,他炼制金丹时,用了兰博基尼上的新鲜露水、白凤凰的羽毛以及麒麟、獬豸和貔貅骨头作为丹魂。

    丹魂工厂.class

    public interface 丹魂工厂 {
        public 露水 createDew();
    
        public 羽毛 createFeather();
    
        public 兽骨[] createBones();
    
        public 金 createGold();
    
        public 银 createSilver();
    
        public 铜 createBronze();
    
    }
    

    思聪丹魂工厂.class

    public class 思聪丹魂工厂 implements 丹魂工厂 {
        @Override
        public 露水 createDew() {
            return new 兰博基尼上的新鲜露水();
        }
    
        @Override
        public 羽毛 createFeather() {
            return new 白凤凰羽();
        }
    
        @Override
        public 兽骨[] createBones() {
            兽骨[] bones = {new 麒麟骨(), new 獬豸骨(), new 貔貅骨()};
            return bones;
        }
    
        @Override
        public 金 createGold() {
            return new 金();
        }
    
        @Override
        public 银 createSilver() {
            return new 银();
        }
    
        @Override
        public 铜 createBronze() {
            return new 铜();
        }
    }
    

    御凤丹魂工厂.class

    public class 御凤丹魂工厂 implements 丹魂工厂 {
        @Override
        public 露水 createDew() {
            return new 中央公园新鲜露水();
        }
    
        @Override
        public 羽毛 createFeather() {
            return new 美洲雕白羽();
        }
    
        @Override
        public 兽骨[] createBones() {
            兽骨[] bones = {new 火鸡骨(), new 北美野牛骨()};
            return bones;
        }
    
        @Override
        public 金 createGold() {
            return new 金();
        }
    
        @Override
        public 银 createSilver() {
            return new 银();
        }
    
        @Override
        public 铜 createBronze() {
            return new 铜();
        }
    
    }
    

    丹.class

    该类与之前的区别就在于,将“准备()”变成了一个抽象方法,由子类去实现

    public abstract class 丹 {
        String name;
        String roomName;
        String creatorName;
        String packageName;
        露水 dew;
        羽毛 feather;
        兽骨[] bones;
        金 gold;
        银 silver;
        铜 bronze;
        List<String> additions = new ArrayList<String>();
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void 收工() {
            System.out.println("炼制完成," + name + "将由" + packageName + "包装\n");
        }
    
        public void 炼制() {
            System.out.println(name + "正在炼制中。。。");
        }
    
        abstract void 准备();
    }
    

    金丹.class

    public class 金丹 extends 丹 {
        丹魂工厂 ingredientFactory;
    
        public 金丹(丹魂工厂 ingredientFactory) {
            this.ingredientFactory = ingredientFactory;
        }
    
    
        @Override
        void 准备() {
            System.out.println("开始炼制" + name);
            dew = ingredientFactory.createDew();
            feather = ingredientFactory.createFeather();
            bones = ingredientFactory.createBones();
            gold = ingredientFactory.createGold();
            System.out.println("构成金丹的丹魂是:" +
                            dew.getClass().getSuperclass().getSimpleName() + "、" +
                            feather.getClass().getSuperclass().getSimpleName() + "和兽骨"
            );
            System.out.println(name + "的丹魂配方由"
                            + dew.getClass().getSimpleName() + "、"
                            + feather.getClass().getSimpleName() + "以及若干兽骨所组成"
            );
            System.out.println("其中兽骨的配方包含:");
            for (int i = 0; i < bones.length; i++) {
                System.out.println("  " + (i + 1) + "." + bones[i].getName());
            }
        }
    }
    

    银丹.class

    public class 银丹 extends 丹 {
        丹魂工厂 ingredientFactory;
    
        public 银丹(丹魂工厂 ingredientFactory) {
            this.ingredientFactory = ingredientFactory;
        }
    
        @Override
        public void 准备() {
            System.out.println("开始炼制" + name);
            dew = ingredientFactory.createDew();
            feather = ingredientFactory.createFeather();
            silver = ingredientFactory.createSilver();
            System.out.println("构成银丹的丹魂是:"
                    + dew.getClass().getSuperclass().getSimpleName() + "和"
                    + feather.getClass().getSuperclass().getSimpleName());
            System.out.println(name + "的丹魂配方由"
                            + dew.getClass().getSimpleName() + "、"
                            + feather.getClass().getSimpleName() + "所组成"
            );
        }
    }
    
    

    思聪的秘制银丹.class

    public class 思聪的秘制银丹 extends 银丹 {
        public 思聪的秘制银丹(丹魂工厂 ingredientFactory) {
            super(ingredientFactory);
            packageName = "斗彩鸡缸杯";
        }
    }
    

    思聪的秘制金丹.class

    public class 思聪的秘制金丹 extends 金丹 {
    
        public 思聪的秘制金丹(丹魂工厂 ingredientFactory) {
            super(ingredientFactory);
            packageName = "斗彩鸡缸杯";
        }
    }
    

    御凤的秘制金丹.class

    public class 御凤的秘制金丹 extends 金丹 {
    
        public 御凤的秘制金丹(丹魂工厂 ingredientFactory) {
            super(ingredientFactory);
            packageName = "首饰盒";
        }
    }
    

    炼丹密室.class

    public abstract class 炼丹密室 {
        public 丹 makeDan(String element) {
            丹 dan;
            dan = createDan(element);
            dan.准备();
            dan.炼制();
            dan.收工();
            return dan;
        }
    
        protected abstract 丹 createDan(String element);
    }
    

    思聪的炼丹密室.class

    public class 思聪的炼丹密室 extends 炼丹密室 {
        @Override
        protected 丹 createDan(String element) {
            丹 dan = null;
            丹魂工厂 ingredientFactory = new 思聪丹魂工厂();
            if (element.equals("金")) {
                dan = new 思聪的秘制金丹(ingredientFactory);
                dan.setName("思聪金丹");
            } else if (element.equals("银")) {
                dan = new 思聪的秘制银丹(ingredientFactory);
                dan.setName("思聪银丹");
            } else if (element.equals("铜")) {
                dan = new 铜丹(ingredientFactory);
                dan.setName("思聪铜丹");
            }
            return dan;
        }
    }
    

    御凤的炼丹密室.class

    public class 御凤的炼丹密室 extends 炼丹密室 {
        @Override
        protected 丹 createDan(String element) {
            丹 dan = null;
            丹魂工厂 ingredientFactory = new 御凤丹魂工厂();
            if (element.equals("金")) {
                dan = new 御凤的秘制金丹(ingredientFactory);
                dan.setName("御凤金丹");
            } else if (element.equals("银")) {
                dan = new 御凤的秘制银丹(ingredientFactory);
                dan.setName("御凤银丹");
            }
            return dan;
        }
    }
    

    测试类

    public class DanTestDrive {
        public static void main(String[] args) {
            炼丹密室 sicongRoom = new 思聪的炼丹密室();
            sicongRoom.makeDan("金");
            sicongRoom.makeDan("银");
            炼丹密室 yufengRoom = new 御凤的炼丹密室();
            yufengRoom.makeDan("金");
        }
    }
    

    运行结果:


    有一天思聪心血来潮,想用一下御凤的丹魂配方,于是他只用改一个地方,即把思聪丹魂工厂改成御凤丹魂工厂。神奇的事情就发生了,只需要改动一处,他的配方就变成了御凤的配方。
    思聪的炼丹密室.class

    public class 思聪的炼丹密室 extends 炼丹密室 {
        @Override
        protected 丹 createDan(String element) {
            丹 dan = null;
            丹魂工厂 ingredientFactory = new 御凤丹魂工厂();
            if (element.equals("金")) {
                dan = new 思聪的秘制金丹(ingredientFactory);
                dan.setName("思聪金丹");
            } else if (element.equals("银")) {
                dan = new 思聪的秘制银丹(ingredientFactory);
                dan.setName("思聪银丹");
            } else if (element.equals("铜")) {
                dan = new 铜丹(ingredientFactory);
                dan.setName("思聪铜丹");
            }
            return dan;
        }
    }
    

    运行结果:


    丹魂工厂这个类便是运用了抽象工厂模式,它以接口的形式提供出了一份创建对象的协议,其中是丹魂的配方,包含露水、白色羽毛和兽骨组合。它只是说丹魂需要这三种成份,具体是用纽约中央公园的新鲜露水还是兰博基尼上面的新鲜露水,它不需要管,由其子类来具体实现,比如御凤丹魂工厂、思聪丹魂工厂。

    结构示意图


    相关文章

      网友评论

        本文标题:工厂模式:摄计魔士和他的炼丹密室

        本文链接:https://www.haomeiwen.com/subject/dnsxgttx.html