浅谈GOF设计模式之工厂模式(四)

工厂模式的本质

实现了创建者和调用者的分离
设计模式的核心的灵魂 就是分工明确化
1.实例化对象,用工厂方法代替new
2.键选择实现类,创建对象管理和控制。从而将调用者跟我们的实现类解耦

工厂模式的分类

1.简单工厂模式:
用来生产同一等级结构(相同父类)中的任意产品。(对于新增产品需要修改已有代码)
2.工厂方法模式:
用来生产同一等级结构中固定产品。(支持增加任意产品)
3.抽象工厂模式:
用来生产不同产品族中的全部产品。(对于增加新的产品无能为力,支持增加产品族)

依赖的基本原则

OCP(开闭原则) :一个软件实体对拓展开放,对修改关闭;
DIP(依赖导致原则):对接口编程,不对实现编程(实现类实现接口)
LoD(迪米特法则):至于直接的朋友通信,而避免和陌生人通信;
也即是说,只与成员变量或者方法的输入输出参数类 中提供的public或protected方法做交互,内部的负责处理不管如何复杂

简单工厂

要点:

-简单工厂也叫 静态工厂模式,就是工厂类一般使用静态方法,通过接受参数的不同来返回不同的对象实例
-对于新增加的产品无能为力,不修改代码,无法增加新产品

代码:

产品块

/**
 * 简单工厂的产品父类(所有的产品的共同父类,也可以是抽象类)
 */
public interface Car {
	void run();
}

/**
 * 奥迪具体产品
 */
public class Audi implements Car {

	@Override
	public void run() {
		System.out.println("奥迪再跑!");
	}

}

/**
 * 比亚迪具体产品
 */
public class Byd implements Car {

	@Override
	public void run() {
		System.out.println("比亚迪再跑!");
	}

}

简单工厂类 也叫静态工厂类

//产品工厂类
public class CarFactory {
	
	public static  Car createCar(String type){
		if("奥迪".equals(type)){
			return new Audi();
		}else if("比亚迪".equals(type)){
			return new Byd();
		}else{
			return null;
		}
	}
}

调用类

/**
 * 简单工厂情况下
 * @author 尚学堂高淇 www.sxt.cn
 *
 */
public class Client02 {   //调用者
	//通过传递不同的产品类型来获取不同的产品对象
	public static void main(String[] args) {
		Car c1 =CarFactory.createCar("奥迪");
		Car c2 = CarFactory.createCar("比亚迪");
		c1.run();
		c2.run();
	}
}

对于新增加的产品无能为力必须修改代码

工厂方法模式

要点:

1.为了避免简单工厂模式的缺点,不完全OCP(开闭原则)
2.工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者独立模板而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类

产品代码块

/**
 * 工厂方法的产品父类(所有的产品的共同父类,也可以是抽象类)
 */
public interface Car {
	void run();
}

/**
 * 奥迪具体产品
 */
public class Audi implements Car {

	@Override
	public void run() {
		System.out.println("奥迪再跑!");
	}

}

/**
 * 比亚迪具体产品
 */
public class Byd implements Car {

	@Override
	public void run() {
		System.out.println("比亚迪再跑!");
	}

}

/**
 * Benz 具体产品
 */
public class Benz implements Car {

	@Override
	public void run() {
		System.out.println("奔驰再跑!");
	}

}

工厂类块

/**
 * 所有工厂类的父类(同样也可以是抽象类)
 */
public interface CarFactory {
	 Car createCar();
}

/**
 * 具体工厂类 Byd
 */
public class BydFactory implements CarFactory {

	@Override
	public /**static*/ Car createCar() {
		return new Byd();
	}

}

/**
 * 具体工厂类 Benz
 */
public class BenzFactory implements CarFactory {

	@Override
	public /**static*/ Car createCar() {
		return new Benz();
	}

}

/**
 * 具体工厂类 Audi
 */
public class AudiFactory implements CarFactory {

	@Override
	public /**static*/ Car createCar() {
		return new Audi();
	}

}

调用者

/**
 * 根据不同的工厂类获取不同的产品对象实例
 */
public class Client {
	public static void main(String[] args) {
		Car c1 = new AudiFactory().createCar();
		Car c2 = new BydFactory().createCar();
		Car c3 = new BenzFactory().createCar();

//		使用静态方法创建对象实例
//		Car c1 = AudiFactory.createCar();
//		Car c2 = BydFactory.createCar();
//		Car c3 = nBenzFactory.createCar();

		c1.run();
		c2.run();
		c3.run();
	}
}

工厂方法变种 – 类似于 抽象工厂方法

产品块

/**
 * 产品的公共父类
 */
public interface Car {
	void run();
}

/**
 *具体产品 byd
 */
public class Byd implements Car {

	@Override
	public void run() {
		System.out.println("比亚迪再跑!");
	}

}

/**
 * 具体产品 byd2
 */
public class Byd2 implements Car {

	@Override
	public void run() {
		System.out.println("比亚迪2再跑!");
	}

}

/**
 * Benz 具体产品
 */
public class Benz implements Car {

	@Override
	public void run() {
		System.out.println("奔驰再跑!");
	}

}

/**
 * Benz2 具体产品
 */
public class Benz2 implements Car {

	@Override
	public void run() {
		System.out.println("奔驰2再跑!");
	}

}

/**
 * 具体产品 Audi
 */
public class Audi implements Car {

	@Override
	public void run() {
		System.out.println("奥迪再跑!");
	}


/**
 * 具体产品 audi2
 */
public class Audi2 implements Car {

	@Override
	public void run() {
		System.out.println("奥迪2再跑!");
	}

}

工厂块

/**
 * 所有工厂类的父类(同样也可以是抽象类)
 */
public abstract class CarFactory {
	public static Car createCar(String carType) {
		return null;
	}

	public abstract Car getCar(String carType);
}


/**
 * 具体工厂类 Byd
 */
public class BydFactory extends CarFactory {

	public static Car createCar(String carType) {
		if("1".equals(carType)) {
			return new Byd();
		}else{
			return new Byd2();
		}
	}

	@Override
	public Car getCar(String carType) {
		return createCar(carType);
	}
}

/**
 * 具体工厂类 Benz
 */
public class BenzFactory extends CarFactory {

	public static Car createCar(String carType) {
		if("1".equals(carType)){
			return new Benz();
		}else{
			return new Benz2();
		}

	}

	@Override
	public Car getCar(String carType) {
		return createCar(carType);
	}

}

/**
 * 具体工厂类 Audi
 */
public class AudiFactory extends CarFactory {

	public static Car createCar(String carType){
		if("1".equals(carType)){
			return new Audi();
		}else{
			return new Audi2();
		}
	}

	@Override
	public Car getCar(String carType) {
		return createCar(carType);
	}
}

调度块

public class Client {
    /**
     * 传递不同的参数 生成不同的工厂产品
     * @param args
     */
    public static void main(String[] args) {
        String factoryType = "Audi";
        Car car1  = getFactory(factoryType).getCar("1");
        Car car2  = getFactory(factoryType).getCar("2");
        factoryType = "Benz";
        Car car3  = getFactory(factoryType).getCar("1");
        Car car4  = getFactory(factoryType).getCar("2");
        factoryType = "Byd";
        Car car5  = getFactory(factoryType).getCar("1");
        Car car6  = getFactory(factoryType).getCar("2");

        car1.run();
        car2.run();
        car3.run();
        car4.run();
        car5.run();
        car6.run();
    }

    public static CarFactory getFactory(String factoryType){
        CarFactory factory = null;
        if("Byd".equals(factoryType)){
            factory = new BydFactory();
        }else if("Benz".equals(factoryType)){
            factory = new BenzFactory();
        }else{
            factory = new AudiFactory();
        }
        return factory;
    }
}

简单工厂和工厂方法的比较

1.结构复杂度
简单工厂对比工厂方法结构简单,只需要一个工厂类。而工厂方法是随着产品族的增加而增加工厂类,工厂类个数会越来越多,增加了结构复杂度
2.代码复杂度
代码复杂度和结构复杂度是一对矛盾,简单工厂模式在结构方面相对简单,在代码方面相对工厂方式模式是复杂的了,简单工厂模式的工厂类随着产品类的增加需要增加修改很多方法和代码;而工厂方法模式每个具体工厂类只完成单一任务,代码简洁
3.客户端编程难度
工厂方法模式 工厂类引入了 接口 从而实现 OCP(开闭原则),但是要在调用方对工厂类进行实例化,而简单工厂类是个静态类,调用方无需实例化,无疑是个优点
4.管理维护上的难度
工厂方法模式完全满足OCP,有很好的拓展性,但是简单工厂也有很好的拓展性(只是需要修改工厂类代码);而工厂方法会因为产品类的增多或者修改导致出现大量的工厂类(基本一个产品一个工厂类)
,而如果产品类修改导致修改工厂类的时候,工厂方法会导致难以追递,而简单工厂只需要修改一个工厂类就可以了
实际上我们一般都用简单工厂模式

抽象工厂模式

1.用来生产不同产品族的全部产品(新增产品无能为力;支持增加产品族)
2.抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种,业务分类是,通过抽象工厂生产需要的对象是一种很好的解决方式

产品类

/**
 * 产品类 - 轮胎
 */
public interface Tyre {
	void revolve();
}

class LuxuryTyre implements Tyre {

	@Override
	public void revolve() {
		System.out.println("旋转不磨损!");
	}
	
}

class LowTyre implements Tyre {

	@Override
	public void revolve() {
		System.out.println("旋转磨损快!");
	}
	
}

/**
 * 产品类  - 椅子
 */
public interface Seat {
	void massage();
}

class LuxurySeat implements Seat {

	@Override
	public void massage() {
		System.out.println("可以自动按摩!");
	}
	
}
class LowSeat implements Seat {

	@Override
	public void massage() {
		System.out.println("不能按摩!");
	}
	
}


package com.bjsxt.factory.abstractFactory;

/**
 * 引擎 - 发动机 产品
 */
public interface Engine {
	void run();
	void start();
}


class LuxuryEngine implements Engine{

	@Override
	public void run() {
		System.out.println("转的快!");
	}

	@Override
	public void start() {
		System.out.println("启动快!可以自动启停!");
	}
	
}

class LowEngine implements Engine{
	
	@Override
	public void run() {
		System.out.println("转的慢!");
	}
	
	@Override
	public void start() {
		System.out.println("启动慢!");
	}
	
}

抽象工厂类 – 创建多个抽象产品


/**
 * 汽车抽象工厂
 */
public interface CarFactory {

	Engine createEngine();
	Seat createSeat();
	Tyre createTyre();
}

public class LowCarFactory implements CarFactory {

	@Override
	public Engine createEngine() {
		return new LowEngine();
	}

	@Override
	public Seat createSeat() {
		return new LowSeat();
	}

	@Override
	public Tyre createTyre() {
		return new LowTyre();
	}


}


public class LuxuryCarFactory implements CarFactory {

	@Override
	public Engine createEngine() {
		return new LuxuryEngine();
	}

	@Override
	public Seat createSeat() {
		return new LuxurySeat();
	}

	@Override
	public Tyre createTyre() {
		return new LuxuryTyre();
	}


}

调度类

public class Client {

	public static void main(String[] args) {
		CarFactory  factory = new LuxuryCarFactory();
		Engine e = factory.createEngine();
		e.run();
		e.start();
		Tyre t = factory.createTyre();
		t.revolve();
		Seat s = factory.createSeat();
		s.massage();

	}
}

总结抽象工厂与工厂方法的区别

1.抽象工厂针对的是多个抽象产品类(多个产品结构等级);
工厂方法针对的是单个抽象产品类(单个产品结构等级);
2.抽象工厂类可以创建每个产品组的单个具体产品实例;(多个具体产品实例)
工厂方法可以创建单个具体产品实例;
3.

工厂模式的要点

简单工厂模式(静态工厂模式):
虽然某种程度不符合设计原理,单实际应用最多
工厂方法模式:
不修改已有类的前提下,通过增加新的工厂类实现拓展
抽象工厂类
不可以增加产品,可以增加产品族(可以理解为具体的工厂的实例已经在抽象类中定义好了,所以增加公共的产品抽象类-在添加具体的)

工厂模式的应用场景

1.JDK中Calendar 中的getInstance()方法
2.JDBC中Connection对象的获取

Connection con = null;
try{
    //通过得到字节码对象的方式加载静态代码块 从而加载注册驱动程序
    Class.forName(String driver);

    //注册URL取得对数据库的连接 获取连接对象
    con = DriverManager.getConnection(uri, username, password);

    ...

    con.close();
}catch(Exception e){
    ...
}finally{
    ...
}

3.Hibernate中SessionFactory创建Session

  Session 是持久层操作的基础,相当于JDBC中的Connnection。

           Configuration config=new Configuration().configure();  //读取默认的hibernate.cfg.xml的文件

           SessionFactory sessionFactory=config.buildSessionFactory();  //通过config创建sessionFactory的实例

           Session session=sessionFactory.openSession();       //获得session

之后,我们就可以调用Session所提供的save,find,flush等方法完成持久化操作:

4.spring中IOC容器创建管理bean对象


/*方式一:通过id获取bean*/
Student student = context.getBean(Student.class);
System.out.println(student.getName());

/*方式二:通过.class文件获取bean*/
Student s = (Student)context.getBean("student") ;
System.out.println(s.getName());

方式三:通过工厂方法来获取bean
静态工厂方法
方法类

package com.cn.cmc.beans;

import java.util.HashMap;
import java.util.Map;

public class StaticStudentFactory {
    private static Map<String,Student> map ;
    static {
        map = new HashMap<String, Student>();
        map.put("叶清逸", new Student(100001,"叶清逸",'M',25)) ;
        map.put("张三", new Student(100002,"张三",'F',22)) ;
    }
    /*通过静态方法获取bean的实例*/
    static Student getBean(String name){
        return map.get(name) ;
    }
}

xml中的配置:

通过静态工厂方法来获取实例
factory-method:对应工厂中配置的获取bean的方法名
constructor-arg:对用获取bean方法传入的参数

<bean id="student1" class="com.cn.cmc.beans.StaticStudentFactory" factory-method="getBean">
    <constructor-arg value="叶清逸"></constructor-arg>
</bean>

5.XML解析时的DocumentBuilderFactory创建解析器对象

(1) javax.xml.parsers 包中的DocumentBuilderFactory, DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。
(2) 调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂。
DocumentBuilderFactory doc=DocumentBuilderFactory.newInstance();
(3) 调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象。
DocumentBuilder db=doc.newDocumentBuilder();
(4) 把要解析的 XML 文档转化为输入流,以便 DOM 解析器解析它
InputStream is= new FileInputStream(“test.xml”);
(5) 调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进行可以利用DOM特性对整个XML文档进行操作了。
Document doc=dombuilder.parse(is);
(6) 得到 XML 文档的根节点
Element root=doc.getDocumentElement();
(7) 得到节点的子节点
NodeList users=root.getChildNodes();

     
     public XmlReader() {
         DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
         try {
             DocumentBuilder domBuilder = domfac.newDocumentBuilder();
             InputStream is = new FileInputStream(new File(
             "C:/Users/sony/Desktop/test.xml"));
             Document doc = domBuilder.parse(is);
             Element root = doc.getDocumentElement();
             NodeList users = root.getChildNodes();
             if (users != null) {
                 for (int i = 0; i < users.getLength(); i++) {
                 Node user = users.item(i);
                 // TEXT_NODE 说明该节点是文本节点
                 // ELEMENT_NODE 说明该节点是个元素节点
                    if (user.getNodeType() == Node.ELEMENT_NODE) {
                     // (7)取得节点的属性值
                     // String email = user.getAttributes()
                     // .getNamedItem("email").getNodeValue();
                     // System.out.println(email);
                     // 注意,节点的属性也是它的子节点。它的节点类型也是Node.ELEMENT_NODE
                     // (8)轮循子节点
                         for (Node node = user.getFirstChild(); node != null; node = node.getNextSibling()){
                             if (node.getNodeType() == Node.ELEMENT_NODE) {
                                if (node.getNodeName().equals("name")) {
                                 String name = node.getNodeValue();
                                 String name1 = node.getFirstChild()
                                 .getNodeValue();
                                 System.out.println("name==" + name);
                                 System.out.println("name1==" + name1);
                                 }
                             if (node.getNodeName().equals("price")) {
                                 String price = node.getFirstChild()
                                .getNodeValue();
                                 System.out.println(price);
                                 }
                             }
                         }
                     }
                 }
             }
             NodeList node = root.getElementsByTagName("string");
            if (node != null) {
                 for (int i = 0; i < node.getLength(); i++) {
                     Node str = node.item(i);
                     String s = str.getFirstChild().getNodeValue();
                     System.out.println(s);
                 }
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
    }
          public static void main(String[] args) {
         XmlReader xmlReader = new XmlReader();
     }
 }
<?xml version="1.0" encoding="GB2312" standalone="no"?> 
<users>
    <user email="www.baidu.com">
        <name>张三</name>
        <age>18</age>
        <sex></sex> 
    </user>
    <user>
        <name>李四</name>
        <age>16</age>
        <sex></sex> 
    </user>
    <user>
        <name>王二麻子</name>
        <age>25</age>
        <sex>不明</sex> 
    </user>
</users>

6.反射中Class对象的newInstance()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值