设计模式笔记-工厂方法模式与抽象工厂模式

设计模式

工厂方法模式与抽象工厂模式

假定场景

有一个披萨店要卖披萨,这需要一段程序。由于披萨有多个类型,可以实现为以下代码:
public class PizzaStore {
    public void orderPizza(String type) {
        Pizza pizza;
        if ("a".equals(type)) {
            pizza = new APizza();
        } else if ("b".equals(type)) {
            pizza = new BPizza();
        } else {
            pizza = null;
        }

        if (pizza != null) {
            pizza.cut();
            pizza.box();
            pizza.finish();
        }

    }
}

上述程序看上去貌似没什么问题。不过,程序写完后首先要考虑这部分的需求是否会发生变化!

假设:店家想增加2种新口味的披萨,删除1种卖的不好的披萨。

此时,就需要修改上述代码。但是,这违反了设计原则–对扩展开放,对修改关闭。要知道,需求通常是会发生变化的,而反复地修改代码通常会使得代码难以维护!

考虑策略设计模式的设计原则之一 – 封装需要变化的部分。新建一个“工厂类”来处理创建对象的需求,如下:

public class PizzaFactory {
    /*
    并非静态方法
    */
    public Pizza createPizza(String type) {
        Pizza pizza;
        if ("a".equals(type)) {
            pizza = new APizza();
        } else if ("b".equals(type)) {
            pizza = new BPizza();
        } else {
            pizza = null;
        }
        return pizza;
    }
}

相应地,修改PizzaStore.java的代码,如下:

public class PizzaStore {
    private PizzaFactory factory;

    public PizzaStore(PizzaFactory factory) {
        this.factory = factory;
    }

    public void orderPizza(String type) {
        //采用PizzaFactory来创建对象
        Pizza pizza = factory.createPizza(type);
        if (pizza != null) {
            pizza.cut();
            pizza.box();
            pizza.finish();
        }

    }
}

上述代码封装了变化的部分,这有利于代码复用。现在需求又发生了变化,如下:

假设:披萨店火了,国内很多地区都想要加盟,但是不同省份需要制作不同口味的披萨来满足当地人的需求。

此时,可以让每个加盟店对应一个特定的工厂来创建披萨。如下:

public abstract class PizzaFactory {
    public abstract Pizza createPizza(String type);
}

public class APizzaFactory extends PizzaFactory{
    @Override
    public Pizza createPizza(String type) {
        Pizza pizza;
        if ("c".equals(type)) {
            pizza = new APizza();
        } else if ("d".equals(type)) {
            pizza = new BPizza();
        } else {
            pizza = null;
        }
        return pizza;
    }
}

上述流程中,a地区的商家可以直接使用自己的APizzaFactory获取一个披萨对象,然后商家自己就可以决定是否box,cut,即商家自己可以不需要PizzaStore。因此,我们无法控制披萨制作的整个流程。为了加强质量控制,可以把PizzaStore抽象出来,做成一个抽象类,然后把制作披萨的工厂方法加入进来,让各个商家实现该类。

public abstract class PizzaStore {

    public void orderPizza(String type) {
        //解耦
        Pizza pizza = createPizza(type);
        if (pizza != null) {
            pizza.cut();
            pizza.box();
            pizza.finish();
        }

    }
    //工厂方法
    protected abstract Pizza createPizza(String type);

}

public class APizzaStore extends PizzaStore {
    @Override
    public Pizza createPizza(String type) {
        Pizza pizza;
        if ("c".equals(type)) {
            pizza = new APizza();
        } else if ("d".equals(type)) {
            pizza = new BPizza();
        } else {
            pizza = null;
        }
        return pizza;
    }
}

可以看到,工厂方法让子类决定需要创建的具体对象,从而实现对象创建过程的封装。

工厂方法模式

在类中定义一个创建对象的接口,让子类决定到底创建哪个具体的对象。从而把对象的实例化推出到了子类。

依赖倒置

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

意思是说,不要让高层组件依赖低层组件,且两种组件都应该依赖抽象。
最开始的代码,PizzaStore依赖着所有具体的Pizza。后续代码的依赖性有所降低,因为我们让高层组件PizzaStore依赖于了低层组件具体的Pizza的抽象。这是工厂方法模式的效果。

倒置思维方式

从顶端到低端的思维是:需要一个披萨店类,这个类可以制作各种披萨,剪切,打包…
倒置:需要制作各种披萨,它们应该有一个共同的接口Pizza.披萨的制作依赖该抽象接口即可,具体的披萨类也依赖该接口,创建具体披萨的接口定义为返回该类型即可。

指导方针

  • 变量不要持有具体类的引用
    我们要针对接口编程,即依赖抽象。
  • 不要让类继承具体类
    如果继承具体,就必然依赖具体类。
  • 不要覆盖基类中已经实现的方法
    如果子类覆盖了基类中的方法,就说明基类不适合被继承

假设

制作披萨需要各种原料,我们不希望各个加盟店自行决定,而是希望指定的原料工厂来提供。

新增一个方法prepare,来准备原材料。

public abstract class Pizza {
    //某种原材料
    private Sault sault;

    public void finish() {

    }
    public void cut() {

    }
    public void box() {

    }

    public abstract void prepare();
}

public interface Sault {
}

不同地区采用不同工厂的原材料,因此可以设置一个原材料工厂的接口:

public interface IngredientFactory {
    Sault createSault();
}

public class AIngredientFactory implements IngredientFactory {
    @Override
    public Sault createSault() {
        return new Sault(){
            @Override
            public String toString() {
                return "a sault";
            }
        };
    }
}

具体披萨的制作:

public class APizza extends Pizza {
    private Sault sault;
    private IngredientFactory ingredientFactory = new AIngredientFactory();
    @Override
    public void prepare() {
        sault = ingredientFactory.createSault();
    }
}

抽象工厂模式

提供接口来创建相关对象或依赖对象的家族,而不需要明确指明具体的类。

比如,上述的ingredientFactory.createSault(),并没有指定创建哪种具体的Sault。我们的客户端代码APizza也从具体的Sault中解耦。

发布了11 篇原创文章 · 获赞 0 · 访问量 675

猜你喜欢

转载自blog.csdn.net/qq_38878217/article/details/104737673