工厂模式

设计模式(Design Pattern):

  设计模式是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结。

设计模式的优点:

  设计模式是优秀的使用案例,使用设计模式可提高代码的重用性,让代码更容易被他人理解,保证代码可靠性。

工厂模式的概念:

  实例化对象,用工厂方法代替new操作

  工厂模式包括工厂方法模式和抽象工厂模式

  抽象工厂模式是工厂方法模式的扩展

工厂模式的意图:

  定义一个接口来创建对象,但是让子类来决定哪些类需要被实例化

  工厂方法把实例化的工作推迟到子类中去实现

什么情况下适合工厂模式?

  有一组类似的对象需要创建

  在编码时不能预见需要创建那种类的实例

  系统需要考虑扩展性,不应依赖于产品类实例如何被创建,组合和表达细节

工厂模式的动机:

  项目中的现状:在软件系统中经常面临着“对象”的创建工作,由于需求的变化,这个对象可能也会发生变化,但它拥有比较稳定的接口。

为此我们需要提供一种封装机制来隔离这个易变对象的变化,从而保持系统会中其它依赖该对象的对象不随着需求变化而变化。

基于项目现状将代码进行如下设计:

  1.尽量松耦合,一个对象的依赖对象的变化与本身无关

  2.具体产品与客户端剥离,责任分割

1.工厂方法模式:

01.创建接口

package com.ltc;
/**
 * 发型接口
 */
public interface HairInterface {
    public void draw();
}

02.创建不同的发型实现该接口

package com.ltc;
/**
 * 右偏分发型
 */
public class RightHair implements HairInterface {

    @Override
    public void draw() {
        System.out.println("-----------------左偏分发型-------------------");

    }

}

package com.ltc;
/**
 * 左偏分发型
 */
public class LeftHair implements HairInterface {

    @Override
    public void draw() {
        System.out.println("-----------------左偏分发型-------------------");

    }
}

03.创建发型工厂生产不同发型

package com.ltc;

import java.util.Map;

public class HairFactory {
    /**
     * 根据类名称来生产对象
     */
    public HairInterface getHairByClassKey(String key){
        Map<String,String> map = new PropertiesReader().getProperties();
        try {
            //用反射创建对象
            HairInterface hair = (HairInterface) Class.forName(map.get(key)).newInstance();
            return hair;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

上述代码中红色字体部分的作用:

代码用反射的方式创建的对象实例,forName(“”)方法中要传全类名,我们可以利用properties文件key-value的存储方式存储全类名,然后读取该文件,返回一个Map根据获得全类名。

读取该文件:

package com.ltc;

import java.io.InputStream;
import java.util.Properties;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class PropertiesReader {

    public Map<String, String> getProperties() {

        Properties props = new Properties();
        Map<String, String> map = new HashMap<String, String>();
        try {

            InputStream in = getClass().getResourceAsStream("type.properties");
            props.load(in);
            Enumeration en = props.propertyNames();
            while (en.hasMoreElements()) {
                String key = (String) en.nextElement();
                String property = props.getProperty(key);
                map.put(key, property);
//                System.out.println(key + "  " + property);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }
}

测试:

package com.ltc;

public class Text1 {
    public static void main(String[] args) {
        HairFactory factory = new HairFactory();
        HairInterface hair1 = factory.getHairByClassKey("right");
        hair1.draw();
        HairInterface hair2 = factory.getHairByClassKey("left");
        hair2.draw();
        
    }
}

结果:

2.抽象工厂模式

以新年和圣诞人们的装扮为例:

新年和圣诞人们都会进行不同的装扮,有新年系列装扮的男孩和女孩,也有圣诞系列新年的男孩和女孩,那我们如何实现新年就进行新年装扮,圣诞就进行圣诞装扮呢?

01.创建男孩和女孩接口人的工厂接口

package com.ltc;
/**
 * 男孩
 */
public interface Boy {
    
    public void drawMan();
}
package com.ltc;
/**
 * 女孩
 */
public interface Girl {
    
    public void drawWomen();
}
package com.ltc;
/**
 * 任务的实现接口
 */
public interface PersonFactory {

    //男孩接口
    public Boy getBoy();
    //女孩接口
    public Girl getGirl();
}

02,分创建新年男孩和新年女孩类实现男孩女孩接口,并创建新年工厂

package com.ltc;
/**
 * 新年系列的男孩儿
 */
public class HNBoy implements Boy {

    @Override
    public void drawMan() {
        System.out.println("-----------------新年系列的男孩子--------------------");
        
    }

}
package com.ltc;
/**
 * 新年系列的女孩儿
 */
public class HNGirl implements Girl{

    @Override
    public void drawWomen() {
        System.out.println("-----------------新年系列的女孩子--------------------");
    }
    
}
package com.ltc;
/**
 * 新年系列加工厂
 */
public class HNFactory implements PersonFactory {

    @Override
    public Boy getBoy() {
        return new HNBoy();
    }

    @Override
    public Girl getGirl() {
        return new HNGirl();
    }
    
}

03.创建圣诞男孩和圣诞女孩实现男孩和女孩接口,创建圣诞工厂

package com.ltc;
/**
*圣诞男孩儿
*/
public class MCBoy implements Boy { @Override public void drawMan() { System.out.println("-----------------圣诞系列的男孩子--------------------"); } }
package com.ltc;

public class MCGirl implements Girl {

    @Override
    public void drawWomen() {
        System.out.println("-----------------圣诞系列的女孩子--------------------");
    }

}
package com.ltc;

public class MCFactory implements PersonFactory {

    @Override
    public Boy getBoy() {
        return new MCBoy();
    }

    @Override
    public Girl getGirl() {
        return new MCGirl();
    }

}

04测试:

        PersonFactory factory1 = new MCFactory();
        Girl girl1 = factory1.getGirl();
        Boy boy1 = factory1.getBoy();
        girl1.drawWomen();
        boy1.drawMan();
        
        System.out.println("==================================================");
        
        PersonFactory factory2 = new HNFactory();
        Girl girl2 = factory2.getGirl();
        Boy boy2 = factory2.getBoy();
        girl2.drawWomen();
        boy2.drawMan();

结果:

工厂方法模式和抽象工厂模式对比:

  01.工厂方法模式是一种极端情况的抽象工厂模式,而抽象工厂模式可以看成是工厂模式的推广

  02.工厂模式用来创建一个产品的等级结构,而抽象工厂是用来创建多个产品的等级结构

  03.工厂模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类

工厂模式的实现帮助我们:

  01.系统在不修改具体工厂角色的情况下引进新的产品

  02.客户端不必关心对象如何创建,明确了职责

  03.更好的理解,面向对象的原则,面向接口编程,而不要面向实现编程

工厂模式适用与哪些场景:

  01.一个系统应当不依赖于产品实力被创立,组成,和表示细节。这对于所有形态的工厂模式都是重要的

  02.这个系统的产品至少有一个产品族

  03.同属于同一产品族的产品是设计成在一起使用。这一约束必须得在系统的设计中体现出来

  04.不同的产品以一系列的接口的面貌实现,从而使系统不依赖于接口实现的细节

原文地址:https://www.cnblogs.com/liutianci/p/8289823.html