设计模式(一):工厂模式

工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,
通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品

–摘自《百度百科》

前言

写文章的目的主要是为了自己知识的巩固,当然也十分希望在此能够得到业界前辈们的指导。

本篇文章围绕:简单工厂模式、工厂方法模式、抽象工厂模式来大致说明。


设计模式的使用是为了提高代码质量、优雅度以及后期更好的重构项目,如果只是为了实现功能而去编写代码就完全没有这个必要了。当然它的缺点会降低一部分可读性。


场景:某汽车工厂->根据不同订单->生产不同品牌的汽车

1.简单工厂模式(Simple Factory Pattern)

定义:由 \color{#FF0000}{一个工厂对象} 决定创建出哪一种产品类的实例。

使用场景:简单工厂模式适用于工厂类对象较少的场景,根据提供的工厂参数来生成不同的产品。无需关心生成过程(new 一个对象的必要条件)

准备工作

//定义一个规范
public interface ICar {
    //生产汽车
    public  void create();
}
//创建一个Audi实现ICar
public class Audi implements ICar {
    @Override
    public void create() {System.out.println("制造Audi");}
}
//创建一个BMW实现ICar
public class BMW implements ICar {
    @Override
    public void create() {System.out.println("制造BMW");}
}

以上代码我们在平时开发中也会经常用到,把公共方法单独抽象出一个类,如果按照我们以往的方法就是

 public static void main(String[] args) {
 	//需要一个Audi
    ICar icar = new Audi();
    icar.create();
    //在需要一个BMW
    ICar icar1 = new BMW();
    icar1.create();
    //这样我们每需要一种汽车,我们都需要去单独创建一个对象.如果品种越来越多,
    //代码就会变的十分臃肿
 }

下面我们使用工厂模式对代码进行优化

1.1 通过类名创建对象
public class CarFactory {
    //通过类名创建对象
    public ICar create(String name){
        if("Audi".equals(name)){
            return  new Audi();
        }else if("BMW".equals(name)){
            return new BMW();
        }else{//在实际中不建议使用null作为返回值,会造成空指针不必要的麻烦.
            return null; 
        }
    }
}
 public static void main(String[] args) {
 	//调用
 	CarFactory factory = new CarFactory();//创建一个工厂对象
 	//需要一个Audi
 	ICar audi = factory.create("Audi");
 	//需要一个BMW
 	ICar bmw = factory.create("BMW");
 	
 	//此类方法根据传入的类名来创建实例,对书写要求较高不允许出现错误。显然不合适
 	
 }
1.2通过包名创建对象
public class CarFactory {
    //通过类名创建对象
    public ICar create(String name){
       try {
            if(!(null == className ||"".equals(className))){
                //通过反射得到类的实例
                return (ICar)Class.forName(className).newInstance();
            }
        }catch (Exception e){
        }
        return null;
    }
}
 public static void main(String[] args) {
 	CarFactory factory = new CarFactory();//创建一个工厂对象
    ICar  bmw = factory.create("com.xx.BMW")
    //此方法通过反射来进行创建,虽然能在一定程度在降低错误,因为我们复制全包名
    //的时候往往不会手动输入(- -! 强行解释一波),显然不能解决我们的问题 继续
 }
1.3 通过类对象创建实例
public class CarFactory {
    //通过类名创建对象
    public ICar create(Class cls){
       try {
            if(cls != null){
                //通过反射得到类的实例
                return cls.newInstance();
            }
        }catch (Exception e){
        }
        return null;
    }
}
public static void main(String[] args) {
 	CarFactory factory = new CarFactory();//创建一个工厂对象
    ICar  bmw = factory.create(BMW.class)
    //你是不是也觉得这样错误率也就大大降低了。
    //相较于原始方法是不是在质量上有那么一丢丢提高
 }

在这里插入图片描述
简单工厂模式

优点:只需传入一个正确合理的参数,就可以获取你所需要的对象 无须知道其创建的过程。

缺点:都由工厂统一创建,工厂类的压力较重,增加新的产品时需要修改工厂类的判断 逻辑,违背开闭原则,不易于扩展相对复杂的结构。

2.工厂方法模式(Factory Method Pattern)

定义:定义一个接口,让实现此接口的类来选择创建哪个类。该工厂不做生产操作,把操作转交给子工厂相当于代理工厂(打个比方:比如富士康帮助苹果生产手机,而苹果本身不生产手机。- - ! 这个比方请不要抬杠)

public interface CarFactory {
    //总工厂,将创建逻辑分给代理工厂一对一创建
    ICar create();
}
//代理工厂1:生产BMW
public class BMWFactory implements CarFactory{
    @Override
    public ICar create() {
        return new BMW();
    }
}
//代理工厂2:生产Audi
public class AudiFactory implements CarFactory{
    @Override
    public ICar create() {
        return new Audi();
    }
}
 public static void main(String[] args) {
        //去Audi工厂要Audi
        CarFactory factory = new AudiFactory();
        ICar audi = factory.create();
        //去BMW工厂要BMW
        factory = new BMWFactory();
        ICar bmw = factory.create();
    }

对工厂方法可以做一些改进:
将CarFactory定义一个抽象类,好处是能添加一些公共的创建条件.

//对工厂方法改进 定义为一个抽象类
public abstract class CarFactory {
    //每个方法创建前的逻辑
    public void preCreate(){

    }

   //公共的方法定义成抽象方法
   abstract ICourse create();
}

在这里插入图片描述
工厂方法模式:
优点:适用于创建对象时需要大量重复的代码
缺点:类的个数较多,复杂度增加,相比第一种抽象了些增加了理解难度。

三、抽象工厂模式(Abastract Factory Pattern)

定义:提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。
什么意思呢?这里解释一下,比方:
1.某一总工厂不单单生产汽车,可能还会生产手机,洗衣机,冰箱等一系列产品。
2.A代理工厂会生产汽车、手机、冰箱、洗衣机。(A生产的产品属于一系列产品 A品牌)
3.B代理工厂会生产汽车、手机、洗衣机。(B生产的产品属于一系列产品 B品牌)
\color{#FF0000}{总工厂就相当于一个产品类的库,所有的产品对象都从同一个接口出现,}
使 \color{#FF0000}{从而使 客户端方面不依赖与具体实现}
下面请看例子:

//所有的工厂都实现这个工厂,一个品牌的抽象
public interface IFactory {
    //制造汽车
    ICar Car();
    //制造电脑
    IComputer computer();
}

//A工厂实现
public class AFactory implements IFactory{
    @Override
    public ICar Car() {
        return new Audi();
    }
    @Override
    public IComputer computer() {
        return new DellComputer();
    }
}
//B工厂实现
public class BFactory implements  IFactory{
    @Override
    public ICar Car() {
        return new Audi();
    }
    @Override
    public IComputer computer() {
        return new DellComputer();
    }
}
   public static void main(String[] args) {
        //A工厂 生产A品牌的一系列
        IFactory factory = new AFactory();
        factory.Car();
        factory.computer();
        //B工厂 生产B品牌的一系列
        IFactory factory1 = new BFactory();
        factory1.computer();
        factory1.Car();
    }

抽象类工厂模式:
优点:扩展性非常强、具体产品在应用层代码隔离,无须关心创建细节、将一个系列的产品统一到一起创建。在spring框架中应该非常广泛
缺点:不符合开闭原则、如果此工厂增加了一个产品,那么所有的子工厂都要实现此方法。
试想一下如果IFactory增加了一个产品,A和B以及更多的子工厂都要实现此类方法。


对本文中 \color{#FF0000}{开闭原则} 的补充:
定义:是指一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。所谓的开闭,也正是对扩展和修改两个行为的一个原则。强调的是用抽象构建框架,用实现扩展细节。可以提高软件系统的可复用性及可维护性。开闭原则,是面向对象设计中最基础的设计原则。它指导我们如何建立稳定灵活的系统,例如:我们版本更新,我尽可能不修改源代码,但是可以增加新功能。请看案例

public class Car {
    private String name;
    private Double price;
    private String color;

    public Car(String name, Double price, String color) {
        this.name = name;
        this.price = price;
        this.color = color;
    }

    public String getName() {
        return name;
    }

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

    public Double getPrice() {
        return price;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

定义一个汽车,某一天商场做活动,对汽车打折扣如果我们直接修改getPrice()或setPrice()方法会存在一定的风险,可能会影响到其他地方的调用结果。那么该如何处理?
----另外编写一个类处理此逻辑

public class CarPrice extends Car{

    public CarPrice(String name, Double price, String color) {
        super(name, price, color);
    }

    public Double OriginPrice(){
        return super.getPrice();
    }

    public Double getPrice(){
        return super.getPrice()*0.5;
    }
}

以上三种方式都有适合自己的场景,没有好坏之分,具体根据实际情况选择。

希望各位看过的伙伴们如果发现了问题能够及时批评指正,在此感谢。

发布了17 篇原创文章 · 获赞 18 · 访问量 1026

猜你喜欢

转载自blog.csdn.net/qq_40409260/article/details/104944695