zoukankan      html  css  js  c++  java
  • 设计模式之工厂模式

    当我们只用new去创建一个类时,我们就在针对这个具体类编程。如果能够不使用具体类,而是针对接口编程,将会对以后扩展有很大方便。

    情景:

    你是一个披萨店的老板,披萨有很多种类。

    我们可能需要这么做

    Pizza orderPizza(String type) {
        Pizza pizza;
        
        if (type == A) {
            pizza = new APizza();
        } else if (type == B) {
            pizza = new BPizza();
        } else if (type == C) {
            pizza = new CPizza();
        }
    
        ... // 制作披萨订单的其他操作
    }

    但是以后我们可能会有D,E,F....之列的更多的披萨。我们必须重新修改这份代码。

    根据“封装变化”的设计原则,我们需要把创建对象的部分封装起来。

    public class SimplePizzaFactory {
        public Pizza createPizza(String type) {
            Pizza pizza = null;
            
            if (type.equals("A")) {
                pizza = new APizza();
            } else if (type.equals("B")) {
                pizza = new BPizza();
            } else if (type.equals("C")) {
                pizza = new CPizza();
            }
            
            return pizza;          
        }
    }

    这样在制作订单时只需在工厂取一个Pizza就可以了。

    public class PizzaStore {
        SimplePizzaFactory factory;
        
        public PizzaStore(SimplePizzaFactory factory) {
            this.factory = factory;
        }
        
        public Pizza orderPizza(String type) {
            Pizza pizza;
            
            pizza = factory.createPizza(type);
            
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
            
        }
        
    }

    ↑ 简单工厂 不是一种设计模式,反而像是一种编程习惯。

    现在有很地区要建立披萨店的分店,你希望所有的店都有相同的流程,但是不同的地区会有不同的口味,比如有些地方只吃DEF口味的披萨,也就是说不同地区要有不同的工厂,没有方法把Pizza的制作活动全部局限于PizzaStore类呢?

    方法是把createPizza放进PizzaStore类中,并设置成抽象方法,具体实现由每一个地区的子类完成。

    public abstract class PizzaStore {
        
        public Pizza orderPizza(String type) {
            Pizza pizza;
            
            pizza = createPizza(type);
            
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
            
        }
    
        abstract Pizza createPizza(String type);
    }

    工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类创建对象的代码解耦了。

     abstract Product factoryMethod(String type) 

    工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

    我们最一开始的代码,PizzaStore的实现是依赖于具体Pizza类的,使用工厂模式后,它已经不再依赖于具体的披萨类,也就是减少了对具体类的依赖。

    设计原则:依赖倒置原则(Dependency Inverseion Principle)

    要依赖抽象,不要依赖具体类。

     这个原则说明了,不要让高层组件依赖底层组件,而且,不管高层组件还是底层组件,两者都应该依赖抽象。

    使用了工厂方法模式之后,PizzaStore类依赖Pizza这个接口,而具体的APizza,BPizza等具体披萨类也依赖于Pizza这个接口,这就是一种依赖倒置。

    ………………

    现在又有一个新的问题

    就是具体Pizza的制作。上面没有写具体披萨的制作过程,默认都是一样的。但是!不同地区用到原料也可能有不同,例如A地产辣椒和B地是不一样的,于是,我们还应该给Pizza写一个原料工厂~~~

    首先为工厂定义一个接口

    public interface PizzaIngredientFactory {
        public Dough createDough();
        public Sauce createSauce();
        public Cheese createCheese();
        public Veggies[] createVeggies();
        public Clams createClam();
    }

    为每一个地区创建一个原料工厂,比如纽约的原料工厂

    public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    
        @Override
        public Dough createDough() {
            return new ThinCrustDough();
        }
    
        @Override
        public Sauce createSauce() {
            return new MarinaraSauce();
        }
    
        @Override
        public Cheese createCheese() {
            return new ReggianoCheese();
        }
    
        @Override
        public Veggies[] createVeggies() {
            Veggies[] veggies = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
            return veggies;
        }
        
        @Override
        public Pepperoni createPepperoni() {
            return new SlicedPepperni();
        }
    
        @Override
        public Clams createClam() {
            return new FreshClams();
        }
    
    }

    抽象的Pizza类

    public abstract class Pizza {
    
        String name;
        Dough dough;
        Sauce sauce;
        Veggies veggies[];
        Cheese cheese;
        Pepperoni pepperoni;
        Clams clams;
        
        abstract void prepare();
    
        public void bake() {
            System.out.println("Bake for 25 minutes at 350.");
        }
    
        public void cut() {
            System.out.println("Cutting the pizza into diagonal slices.");
        }
    
        public void box() {
            System.out.println("Place pizza in official PizzaStore box.");
        }
        
        void setName(String name) {
            this.name = name;
        }
        
        String getName() {
            return name;
        }
        
        public String toString() {
            return name;
        }
    
    }

    具体的Pizza类。每个Pizza的制作流程其实是一样的。只有原料不同,同时原料会和地点有关。为具体的类添加一个原料工厂。

    public class CheesePizza extends Pizza {
        
        PizzaIngredientFactory ingredientFactory;
        
        public CheesePizza(PizzaIngredientFactory ingredientFactory) {
            this.ingredientFactory = ingredientFactory;
        }
    
        @Override
        void prepare() {
            System.out.println("Preparing " + name);
            dough = ingredientFactory.createDough();
            sauce = ingredientFactory.createSauce();
            cheese = ingredientFactory.createCheese();
        }
    
    }

    纽约的PizzaStore类

    public class NYPizzaStore extends PizzaStore {
    
        @Override
        Pizza createPizza(String item) {
            Pizza pizza = null;
            PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
            
            if (item.equals("cheess")) {
                pizza = new ChessPizza(ingredientFactory);
                
            } else if (item.equals("veggie")) {
                pizza = new VeggiePizza();
                pizza.setName("New York Style Veggie Pizza.");
            }
            // else if .... 还有其他种类的Pizza 
            
            return pizza;
        }
        
    }

    完成~~

    我们引入了新类型的工厂,也就是所谓的抽象工厂,来创建披萨家族。

    抽象工程模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

    抽象工厂允许客户使用抽象类的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体产品中被解耦。

    类图

    工厂方法模式通过继承,而抽象工厂模式是通过组合实现。

    抽象工厂是用来创建一个产品家族的抽象类型,可以把一群相关产品集合起来。

  • 相关阅读:
    Dubbo探索(七)
    Dubbo探索(六)
    Dubbo探索(五)
    Dubbo探索(四)
    Redis主节点内存占用过高
    修改RedHat 7.2 进程最大句柄数限制
    Linux 数据分析常用 shell命令
    流处理
    根域名服务器
    并发与并行(concurrency vs parallesim)
  • 原文地址:https://www.cnblogs.com/wenruo/p/6529558.html
Copyright © 2011-2022 走看看