java的工厂模式

简单工厂

简单工厂(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例,但是他不属于GOF23种设计模式。简单工厂使用与工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心
比如学校里面的课程,有各种各样的课程,每个课程都有记笔记的行为,数学课记数学笔记,语文课记语文笔记,英语课记英语笔记等等,所以定义个课程的标准ICourse接口:

public interface ICourse {
    void takeNote();
}

创建一个ChineseCourse课程来实现课程接口:

public class ChineseCourse implements ICourse {
    @Override
    public void takeNote() {
        System.out.println("语文课笔记");
    }
}

客户端调用代码:

public class TestSimpleFactory {
    public static void main(String[] args) {
        // 方式一
        ICourse course = new ChineseCourse();
        course.takeNote();
    }
}

上面的代码,父类ICourse指向子类ChineseCourse的引用,应用层代码需要依赖ChineseCourse,如果业务扩展,继续增加EnglishCourse甚至更多,那么我们客户端的依赖会变得越来越臃肿。因此,需要想办法把这种依赖减弱,把创建细节隐藏。虽然目前的代码中,创建对象的过程并不复杂,但从代码设计角度来讲不易于扩展。利用简单工厂模式对代码进行优化,先增加课程EnglishCourse类:

public class EnglishCourse implements ICourse {
    @Override
    public void takeNote() {
        System.out.println("英语课笔记");
    }
}

创建CourseFactory工厂类:

public class CourseFactory {
    public static ICourse create(String name){
        // 方式二
        if (name.equals("Chinese")){
            return new ChineseCourse();
        }else if (name.equals("English")){
            return new EnglishCourse();
        }else {
            return null;
        }
    }
}

修改客户端调用代码:

public class TestSimpleFactory {
    public static void main(String[] args) {
        // 方式二
        ICourse course = new CourseFactory().create("Chinese");
        course.takeNote();
    }
}

在这里插入图片描述
客户端调用简单了,但是随着业务的扩展,需要增加其他的课程,那么工厂中的creat()就要根据产品链的丰富每次都要修改代码逻辑。不符合开闭原则。因为,我们对简单工厂还可以继续优化,可以采用反射技术:

public class CourseFactory {
    public static ICourse create(String className){
        // 方式三
        try {
            if(null != className && !"".equals(className)){
                return (ICourse)Class.forName(className).newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

客户端调用代码:

public class TestSimpleFactory {
    public static void main(String[] args) {
        // 方式三
        ICourse course = new CourseFactory().create("org.factoryFuxi.simplefactory.EnglishCourse");
        course.takeNote();
    }
}

优化后,产品不断丰富不需要修改CourseFactory的中代码。但是方法参数是字符串,可控性有待提升,而且还需要强制转型,继续优化工厂:

public class CourseFactory {
    public static ICourse create(Class<? extends ICourse> clazz){
        // 方式四
        try {
            if (null != clazz){
                return clazz.newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

客户端调用代码:

public class TestSimpleFactory {
    public static void main(String[] args) {
        // 方式四
        ICourse course = CourseFactory.create(ChineseCourse.class);
        course.takeNote();
    }
}

简单工厂的在JDK源码中的提现,例如Calendar类,Calendar.getInstance()方法中
在这里插入图片描述
输入时区以及时间地区则可得到实例
简单工厂的缺点:工厂类的职责相对过重,不易于扩展过于复杂的产品结构。

工厂方法

工厂方法模式(Factory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。
工厂方法模式主要解决产品扩展的问题,在简单工厂中,随着产品链的丰富,如果每个课程的创建逻辑有区别的话,工厂的职责会变的越来越多,有点像万能工厂,并不便于维护。根据单一职责原则我们将只能继续拆分,专人干专事。Java课程由Java工厂创建,Python课程由Python工厂创建,对工厂本身也做一个抽象。
创建ICourseFactory接口:

public interface ICourseFactory {
    ICourse creat();
}

在分别创建子工厂,ChineseCourseFactory类:

public class ChineseCourseFactory implements ICourseFactory{
    @Override
    public ICourse creat() {
        return new ChineseCourse();
    }
}

EnglishCourseFactory类:

public class EnglishCourseFactory implements ICourseFactory{
    @Override
    public ICourse creat() {
        return new EnglishCourse();
    }
}

客户端测试代码:

public class Test {
    public static void main(String[] args) {
        ICourseFactory factory = new EnglishCourseFactory();
        ICourse course = factory.creat();
        course.takeNote();
    }
}

类图如下:
在这里插入图片描述
工厂方法适用于以下场景:
1、创建对象需要大量的重复代码。
2、客户端(应用层)不依赖于产品类实例如何被创建,实现等细节。
3、一个类通过其子类来指定创建哪个对象
缺点:
1、类的个数容易过多,增加复杂度。
2、增加了系统的抽象性和理解难度。

抽象工厂

抽象工厂模式(Abastract Factory Pattern)是指提供一个创建一系列相关或者相互依赖对象的接口,无序指定他们具体的类。客户端(应用层)不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
首相要了解两个概念,产品等级结构和产品族,如图所示:

在这里插入图片描述
从上图中看出有正方向,圆形和菱形三种图形,相同颜色深浅的代表同一个产品族。同样的可以从生活中举例,比如美的电器生产多种家用电器。那么上图中,颜色最深的正方形代表美的的洗衣机,颜色最深的圆形代表美的的空调,颜色最深的菱形代表美的的热水器,颜色最深的一排都属于美的的品牌,都是美的电器这个产品族。再看右侧的菱形,颜色的深浅代表不用的品牌。
在这里插入图片描述
通过上面两张图的对比理解,以课程为例,除了节本的ICourse之外,每个课程还有家庭作业IHomework以及复习的接口IReview:

public interface IHomework {
    void doHomework();
}
public interface IReview {
    void review();
}

然后创建一个抽象工厂CourseFactory类,抽象工厂是用户的主入口,在spring中应用最广泛的一种设计模式,易于扩展:

public abstract class CourseFactory {

    public void init(){
        System.out.println("初始化数据");
    }

    protected abstract IReview createVideo();

    protected abstract IHomework createNote();
}

创建语文课产品族,语文课作业以及复习语文知识:

public class ChineseHomework implements IHomework{
    @Override
    public void doHomework() {
        System.out.println("语文课作业");
    }
}
public class ChineseReview implements IReview {
    @Override
    public void review() {
        System.out.println("语文课复习");
    }
}

创建语文课产品族的具体工厂ChineseCourseFactory:

public class ChineseCourseFactory extends CourseFactory{

    @Override
    protected IReview createReview() {
        super.init();
        return new ChineseReview();
    }

    @Override
    protected IHomework createHomework() {
        return new ChineseHomework();
    }
}

英语课也是如此,看客户端调用:

public class TestAbstractFactory {
    public static void main(String[] args) {
        CourseFactory courseFactory = new ChineseCourseFactory();
        IHomework hm = courseFactory.createHomework();
        hm.doHomework();
        IReview re = courseFactory.createReview();
        re.review();
    }
}

上面的代码完整地描述了两个产品族Chinese课程以及English课程,也描述了两个产品等级做作业以及复习。抽象工厂非常完美清晰地描述一层复杂的关系,但是,如果继续扩展产品等级,则我们的代码从抽象工厂到具体工厂全部要调整,很现任不符合开闭原则,因为抽象工厂也是有缺点的:
1、规定了所有可能被创建的产品集合,产品族中扩展产品困难,需要修改抽象工厂的接口。
2、增加了系统的抽象性和理解难度。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值