软件设计模式-工厂模式

阅读数:84 评论数:0

跳转到新版页面

分类

架构学

正文

设计原则:要依赖抽象,不要依赖具体类。

这个原则听起来很像是“针对接口编程,不针对实现编程”,然而这里更强调“抽象”,不能让高层组件依赖底层组件,而且,不管高层或低层组件,“两者”应该依赖于抽象。

一、简单工厂

1、模式描述

这其实不是一个设计模式,反而比较像一种编程习惯

利用一个静态方法定义一个简单工厂是很常见的方法,常称为静态工厂。虽然可以在使用方法时,不用实例化方法,但也不能通过继承来改变创建方法的行为。

简单工厂模式实质是由一个工厂类根据传入的参数,决定应该创建哪一个产品类对象。

2、示例

(1)写一个简单的Car汽车接口,有不同的实现子类。

// 汽车接口
public interface Car {
 
    void run();
}
 
// 汽车产品一:实现类--BMW
public class Bmw implements Car{
 
    @Override
    public void run() {
        System.out.println("----宝马车启动----");
    }
}
 
// 汽车产品二:实现类--Benz
public class Benz implements Car{
    @Override
    public void run() {
        System.out.println("----奔驰车启动----");
    }
}
 
// 汽车产品三:实现类--Audi

(2)静态工厂类

public class CarStaticFactory {
 
    public static Car getCar(String carName){
        if (carName.equals("BMW")){
            return new Bmw();
        }else if (carName.equals("Benz")){
            return new Benz();
        }
        return null;
    }
}

虽然这种方式分离了创建和使用,用户无需关心创建的过程,降低了耦合,但违背了设计模式的“开闭原则”,如果后期需要增加更多的产品类,则必须对工厂类进行修改。

(3)使用反射进行改进

为了解决每增加一个产品,就得修改工厂类,增加一个else if分支,使用反射进行改进。

public class CarStaticFactory {
 
    public static Car getCar(String carName){
        if (carName.equals("BMW")){
            return new Bmw();
        }else if (carName.equals("Benz")){
            return new Benz();
        }
        return null;
    }
 
    // 通过反射获取类实例
    public static Car getCarByReflect(String classPath){
        Car car = null;
        try {
            Class clazz = Class.forName(classPath);
            //创建对象
            car = (Car) clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return car;
    }
}

测试类

public class Test {
    public static void main(String[] args) {
 
        // 静态工厂
//        Car car = CarStaticFactory.getCar("BMW");
        Car car = CarStaticFactory.getCarByReflect("com.example.demo.factory.Bmw");
        car.run();
 
    }
}

我们在实际如此使用时,会发现类的全路径会耦合在使用代码里。

(4)使用配置文件再次改造

增加配置文件,读取配置文件获取对应的类路径变量,再反射创建实例。

创建一个配置文件applicationContext.properties文件。

bmw=com.example.demo.factory.Bmw
benz=com.example.demo.factory.Benz
/**
 * @description: 模拟bean工厂类
 * @author: stwen_gan
 * @date: 
 **/
public class BeanFactory {
    /**
     * 通过properties类获取配置文件中的配置
     */
    private static Properties properties = new Properties();
 
    static {
        try {
            //1. 获得IO输入流
            InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.properties");
            //2. 加载流
            properties.load(inputStream);
            //3. 关闭流
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    public static Car getCarByName(String beanName){
        Car car = null;
        try {
            Class clazz = Class.forName(properties.getProperty(beanName));
            //创建对象
            car = (Car) clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return car;
    }
}

这样我们就实现了一个通用的工厂模式。

其实,Spring在启动时通过xml、JavaConfig、注解扫描等方式注册bean,我们需要某个bean实例时,就可以通过调用getBean方法从ApplicationContext中获取容器的bean对象。Spring中BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,所以说,虽然简单的静态工厂模式有缺陷,但正因为它简单方便,可通过一定的改造,在某些场景更实用方便

二、工厂方法模式

1、模式描述

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

可以认为工厂方法是简单工厂的进一步延伸,这是因为简单工厂违反了开放-封闭原则,而工厂方法却没有这个问题。

将产品的“实现”从“使用”中解耦,同时可以定义一个默认的工厂方法来产生某些具体的产品,这样一来,即使创建者没有任何子类,依然可以创建产品。简单工厂把全部的事情,在一个地方都处理完,然而工厂方法却是创建一个框架,让子类决定如何实现。将创建对象的代码集中在一个对象或方法中,可以避免代码中的重复,并且更方便以后的维护。

在抽象的Creator中,任何其他实现的方法,都可能使用到这个工厂方法所造出来的产品,但只有子类真正实现这个工厂方法并创建产品。其中的子类的确看起来很像简单工厂。

2、示例

(1)创建工厂子类

// 抽象接口
public interface ICarFactory {
 
    Car getCarByFactory();
}
 
// bmw 工厂子类 (某一类型的工厂,只生产bmw车型)
public class BmwFactory implements ICarFactory{
    @Override
    public Car getCarByFactory() {
        return new Bmw();
    }
}
 
// benz 工厂子类 (某一类型的工厂,只生产benz车型)
public class BenzFactory implements ICarFactory{
    @Override
    public Car getCarByFactory() {
        return new Benz();
    }
}
 
// ....

(2)测试

public class Test {
    public static void main(String[] args) {
 
//        // 静态工厂
//        Car car = CarStaticFactory.getCar("BMW");
//        car.run();
 
        // 工厂方法
        Car car = new BmwFactory().getCarByFactory();
        car.run();
        
    }
}

 

三、抽象工厂模式

1、模式描述

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

2、示例

(1)创建工厂类

/**
 * @description: 抽象工厂--可生产不同产品组产品
 * @author: stwen_gan
 * @date: 
 **/
public interface Factory {
 
    Car getCarByFactory();
 
    Plane getPlaneByFactory();
 
    // 其他产品组。。。
}
 
// 工厂一:可生产宝马汽车和客机
public class FactoryOne implements Factory{
 
    @Override
    public Car getCarByFactory() {
        return new Bmw();
    }
 
    @Override
    public Plane getPlaneByFactory() {
        return new AirPlane();
    }
}
 
// 工厂二:可生产奔驰汽车和战斗机
public class FactoryTwo implements Factory{
 
    @Override
    public Car getCarByFactory() {
        return new Benz();
    }
 
    @Override
    public Plane getPlaneByFactory() {
        return new BattlePlane();
    }
}

(2)测试

public class Test {
    public static void main(String[] args) {
 
        // 抽象工厂
        Car car1 = new FactoryOne().getCarByFactory();
        car1.run();
        Plane plane1 = new FactoryOne().getPlaneByFactory();
        plane1.fly();
 
        Car car2 = new FactoryOne().getCarByFactory();
        car2.run();
        Plane plane2 = new FactoryOne().getPlaneByFactory();
        plane2.fly();
 
    }
}

 




相关推荐

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。 设计原则:

观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。 设计原则:</st

装饰者模式:动态将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。 设计原则:类应该对扩展

一、概述 单件模式:确保一个类只有一个实例,并提供一个全局访问点。对于频繁使用的对象,特别是重量级对象,可以省略创建对象所花费的时间,同时降低GC压力。 采用私有构造器。Spring容器中的Bean默

一、概述 命令模式:将动作的请求者从动作的执行者中解耦。 发起请求的对象是调用者,调用者只要调用命令对象的execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何工作的。 命

一、概述 适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。 以上是对象适配器的图。 以上是类适配器的图。

外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。 适配器是包装一个类,而外观模式是包装多个

模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。 算法内的步骤不要切割的太细,否则会较没有弹性。 钩子是

迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各

组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。使用组合模式,我们能把相同的操作应用在组合和个别对象上。