喵星之旅-沉睡的猫咪-工厂类型设计模式

 

一、简单工厂模式

创建一个工厂类,里面写方法负责创建对象。提供创建实例的功能,而无需关心具体实现。锅是由调用者和工厂一起负责的。

由于如果创建一个对象,不单是工厂类内部的问题,调用者往里面传入信息了,所以一旦出现问题是双方的问题。他解耦的结果是虽然锅没彻底甩出去,但是找了一个一起背锅的。

类关系图如下:

产品接口: 

package create.simplefactory;

public interface Food {
    public void cook();
}

具体产品1: 

package create.simplefactory;

public class Jiucaijidan implements Food {
    public void cook() {
        System.out.println("韭菜鸡蛋做好了");
    }
}

 具体产品2: 

package create.simplefactory;

public class Xihongshijidan implements Food {
    public void cook() {
        System.out.println("西红柿鸡蛋做好了");
    }
}

工厂类:

package create.simplefactory;

public class FoodFactory {
    public Food createByName(String name) {
        if ("Jiucaijidan".equals(name)) {
            return new Jiucaijidan();
        } else if ("Xihongshijidan".equals(name)) {
            return new Xihongshijidan();
        }
        return null;
    }
    public Food createByClassname(String name) {
        try {
            if (name != null && !"".equals(name)) {
                return (Food) Class.forName(name).newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public Food createByClass(Class<? extends Food> clazz) {
        try {
            if (clazz != null) {
                return clazz.newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

 测试类:

package create.simplefactory;

public class Test {

    public static void main(String[] args) {
        Food f1 = new FoodFactory().createByName("Jiucaijidan");
        f1.cook();
        
        Food f2 = new FoodFactory().createByClassname("create.simplefactory.Xihongshijidan");
        f2.cook();
        
        Food f3 = new FoodFactory().createByClass(Xihongshijidan.class);
        f3.cook();
    }

}

 

二、工厂模式

对上面的进行包装,将类型相同、有关联的放在一起,上面创建接口,外界通过接口使用工厂。让工厂彻底成为背锅侠。这里使用工厂时,已经不需要调用者参与了,所以除了问题都是工厂相关的,完美甩锅。

关系图如下:

产品接口:

package create.factory;

public interface Food {
    public void cook();
}

具体产品1:

package create.factory;

public class Jiucaijidan implements Food {
    public void cook() {
        System.out.println("韭菜鸡蛋做好了");
    }
}

具体产品2:

package create.factory;

public class Xihongshijidan implements Food {
    public void cook() {
        System.out.println("西红柿鸡蛋做好了");
    }
}

工厂接口:

package create.factory;

public interface FoodFactory {
    public Food create();
}

具体工厂1:

package create.factory;

public class JiucaiFactory implements FoodFactory {
    public Food create() {

        return new Jiucaijidan();

    }
}

具体工厂2:

package create.factory;

public class XihongshiFactory implements FoodFactory {
    public Food create() {
            return new Xihongshijidan();
        
    }
}

测试类:

package create.factory;

public class Test {

    public static void main(String[] args) {
        FoodFactory ff1 = new XihongshiFactory();
        FoodFactory ff2 = new JiucaiFactory();
        Food f1 = ff1.create();
        Food f2 = ff2.create();
        f1.cook();
        f2.cook();
         
    }

}


三、抽象工厂模式

考虑工厂的出现,将里面的简单工厂用工厂替换,就是抽象工厂。而且可以出现多级抽象工厂。

如果工厂进行背锅,里面有一些质量好的工厂就会有意见,所以内部分裂了,内部进行甩锅,就是抽象工厂。工厂总接口越稳定、内部背锅规则越详细,那么甩锅的设计就更完善、这个抽象工厂越成功。

关系图如下(只是其中一种展现方式):

具体产品1:

package create.abstractfactory;

public class XiangyouJiucaijidan  implements Condiment,Food {

    @Override
    public void add() {
        System.out.println("添加香油的");
    }

    @Override
    public void cook() {
        System.out.println("韭菜鸡蛋做好了");
    }

}

具体产品2:

package create.abstractfactory;

public class XiangyouXihongshijidan implements Condiment, Food {

    @Override
    public void add() {
        System.out.println("添加香油的");
    }

    @Override
    public void cook() {
        System.out.println("西红柿鸡蛋。");
        
    }

}

具体产品3:

package create.abstractfactory;

public class JijingJiucaijidan implements Food, Condiment {
    public void cook() {
        System.out.println("韭菜鸡蛋做好了");
    }

    @Override
    public void add() {
        System.out.println("添加鸡精。");
    }
}

具体产品4:

package create.abstractfactory;

public class JijingXihongshijidan implements Food, Condiment {
    public void cook() {
        System.out.println("西红柿鸡蛋做好了");
    }

    @Override
    public void add() {
        System.out.println("添加鸡精。");
        
    }
}

产品分类1: 

package create.abstractfactory;

public interface Condiment {
    void add();
}

 产品分类2:

package create.abstractfactory;

public interface Food {
    public void cook();
}

 总产品接口:

package create.abstractfactory;

public interface CookFactory {
    public Food createXihongshijidan() ;
    public Food createJiucaijidan() ;
}

 分类产品工厂1:

package create.abstractfactory;

public class JijingFactory implements CookFactory {
    public Food createXihongshijidan() {

        return new JijingXihongshijidan();

    }
    public Food createJiucaijidan() {
        
        return new JijingJiucaijidan();
        
    }
}

 分类产品工厂2:

package create.abstractfactory;

public class XiangyouFactory implements CookFactory {
    public Food createXihongshijidan() {

        return new XiangyouXihongshijidan();

    }
    public Food createJiucaijidan() {
        
        return new XiangyouJiucaijidan();
        
    }
}

测试类:

package create.abstractfactory;

public class Test {

    public static void main(String[] args) {
        CookFactory ff1 = new JijingFactory();
        CookFactory ff2 = new XiangyouFactory();
        Food f1 = ff1.createXihongshijidan();
        Food f2 = ff2.createXihongshijidan();
        
        f1.cook();
        f2.cook();
         
    }

}

 


四、多级抽象工厂模式

考虑工厂模式,将简单工厂用抽象工厂替换。

如果工厂接口层级较高,需要考虑如果尽量少的改动上方接口进行接口分层,胡乱分层会出问题。层级越靠上的改动频率应该越低。

对于工厂之上的抽象系列,也可能是单纯的工厂里面进行产品分类形成的,可能是多个工厂合道一起也可能是一个工厂拆分。如果是拆分就看拆分的详细程度,决定了抽象程度。不管是合并还是拆分,其实都需要重构。想要一开始就设计完美是不可能的.


五、抽象工厂的实现步骤(以上面的抽象工厂为例)

1、分析具体的产品特性,找出2中不同类别的特征。

比如:香油的韭菜鸡蛋、鸡精的韭菜鸡蛋、香油的西红柿鸡蛋、鸡精的西红柿鸡蛋。

那么一个菜可以有主料和调两部分。

2、考虑2类特性那一个变化的几率比较低。

我个人认为调料新品种的出现会频率更高,那么就认为主料的变化相对固定。

3、根据变化频率低的创建总接口

接口:菜肴

里面两个方法:做一个西红柿鸡蛋

做一个韭菜鸡蛋

如果认为是调料稳定,那么这里应该是两外的两个方法:添加香油的食物、添加鸡精的食物。

4、根据总接口和具体菜肴,创建不同的工厂类

第一个工厂往里面添加香油

第二个工厂往里面添加鸡精

5、这时候考虑变化,我们认为调料是变化的,就会出现新的调料,比如生抽。

那么我们的变化是总接口不变化!!,然后添加一个新的工厂类。

如果总接口先变化,那么说明设计错误。

 

ps:项目地址  svn://47.105.188.20/kitty/2%E3%80%81code/pattern    用户名密码:reader/reader

posted @ 2020-02-25 21:45  喵星兔  阅读(377)  评论(0编辑  收藏  举报