三种工厂模式

Posted by New Boy on March 8, 2018

前言

之前在网上看了很多关于工厂模式的文章,之前看完就觉得懂了,可之后又忘了,上周把实习结束了,匆匆告别,匆匆回校。很棒的实习经历,有空再写。回校后打算理一遍设计模式,自己实现一遍,当是加深一下记忆,为之后正式的工作打好基础。先写写工厂模式。

工厂模式主要分为三种,简单工厂模式,工厂模式,以及抽象工厂模式。说到工厂模式,其实我觉得在类和类之间的解耦起到了比较关键的作用,还是要在适当的场景下使用适当的设计模式。

以实际的例子讲讲这三种设计模式吧,我觉得例子是最能加强记忆的。

简单工厂模式

“民以食为天”,就举食物相关的例子。

简单起见,为食物抽象出三个属性:成本,售价,名字。创建抽象类:

public abstract class Food {
    private int price;
    private int cost;
    private String name;

    public Food() {
    }

    public Food(int price, int cost, String name) {
        this.price = price;
        this.cost = cost;
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public int getCost() {
        return cost;
    }

    public void setCost(int cost) {
        this.cost = cost;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Food{" +
                "price=" + price +
                ", cost=" + cost +
                ", name='" + name + '\'' +
                '}';
    }
}

设想了两个类继承Food类,一个是“炒饭”,一个是“面条”。

FriedRice:

public class FriedRice extends Food {

    public FriedRice() {
        this(100, 20, "FriedRice");
    }

    public FriedRice(int price, int cost, String name) {
        super(price, cost, name);
    }

    @Override
    public String toString() {
        return "FriedRice{" +
                "price=" + super.getPrice() +
                ", cost=" + super.getCost() +
                ", name='" + super.getName() + '\'' +
                '}';
    }
}

Noodles:

public class Noodles extends Food {
  
    public Noodles() {
        this(50, 10, "Noodles");
    }

    public Noodles(int price, int cost, String name) {
        super(price, cost, name);
    }
    @Override
    public String toString() {
        return "Noodles{" +
                "price=" + super.getPrice() +
                ", cost=" + super.getCost() +
                ", name='" + super.getName() + '\'' +
                '}';
    }
}

对于简单工厂模式而言,只是提供了一个生产对象的工厂,看网上大部分通过switch或者if进行实例化对象,这里我是用了反射去实现,感觉代码的可维护性会更好,当然,反射的效率是个问题,factory中添加了缓存进行了适当的优化。

public class FoodFactory {

    private ConcurrentHashMap<String, Class> classCache;

    FoodFactory() {
        classCache = new ConcurrentHashMap<>();
    }

    public Object getClz(String clzName) throws Exception {
        Object obj;
        if (classCache.get(clzName) != null) {
            obj = classCache.get(clzName).newInstance();
        } else {
            obj = Class.forName(clzName).newInstance();
        }
        return obj;
    }
}

测试类:

public class Main {
    public static void main(String[] args) {
        FoodFactory foodFactory = new FoodFactory();
        String foodName = "com.dmc.DesignPatterns.simpleFactory.FriedRice";
        Object food = chooseFood(foodName, foodFactory);
        System.out.println(food.toString());
    }

    public static Object chooseFood(String foodName, FoodFactory foodFactory) {
        Object food = null;
        try {
            food = foodFactory.getClz(foodName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return food;
    }
}

写完觉得简单工厂模式还是觉得单个工厂难以维护,而且在效率上有一定的局限,结构也不是很清晰。就比如你一个车间要去加工所有类型的产品,给人的感觉就是“乱”。

工厂模式

在简单工厂模式的基础上,抽象出“FoodFactory”的接口,每一种食物都交由相对应的工厂实现。比较好理解:

public interface FoodFactory {
    Food createFood();
}
//炒饭工厂
public class FriedRiceFactory implements FoodFactory {
    @Override
    public Food createFood() {
        Food food = new FriedRice();
        return food;
    }
}
//面条工厂
public class NoodlesFactory implements FoodFactory {
    @Override
    public Food createFood() {
        Food food = new Noodles();
        return food;
    }
}

测试类:

public class Main {
    public static void main(String[] args) {
        FriedRiceFactory friedRiceFactory = new FriedRiceFactory();
        Food friedRice = friedRiceFactory.createFood();
        System.out.println(friedRice.toString());

        NoodlesFactory noodlesFactory = new NoodlesFactory();
        Food noodles = noodlesFactory.createFood();
        System.out.println(noodles.toString());
    }
}

抽象工厂模式

考虑以下场景:有饭店A和饭店B,两家饭店都会制作炒饭和面条,但其成本 或者售价不同,那么抽象工厂便有其用武之地。

抽象出一个”饭店接口”

public interface AbstractRestaurant {
    Food createRice();

    Food createNoodles();
}

分别实现A饭店和B饭店

public class RestaurantA implements AbstractRestaurant {
    @Override
    public Food createRice() {
        Food food = new FriedRice(20, 5, "FriedRiceA");
        return food;
    }

    @Override
    public Food createNoodles() {
        Food food = new Noodles(30, 15, "NoodlesA");
        return food;
    }
}
public class RestaurantB implements AbstractRestaurant {
    @Override
    public Food createRice() {
        Food food = new FriedRice(59, 14, "FriedRiceB");
        return food;
    }

    @Override
    public Food createNoodles() {
        Food food = new Noodles(34, 21, "NoodlesB");
        return food;
    }
}

测试程序:

public class Main {
    public static void main(String[] args) {
        RestaurantA A = new RestaurantA();
        RestaurantB B = new RestaurantB();

        Food AFriedRice = A.createRice();
        Food ANoodles = A.createNoodles();
        System.out.println(AFriedRice);
        System.out.println(ANoodles);

        Food BFriedRice = B.createRice();
        Food BNoodles = B.createNoodles();
        System.out.println(BFriedRice);
        System.out.println(BNoodles);
    }
}

总结

很浅的个人理解,希望工作中能加深理解。。。