前言:最近找工作没有怎么更新博客了,找工作的过程中被问到很多关于设计模式的问题。有的叫我画类图,有的叫手写代码实现一下,最有意思的是面试有米科技时面试官问java api中那些用到了设计模式(本人表示很想进去)。经过这个问题之后令我深思了,我们学习了这么多设计模式到底有没想过该怎么用,那些设计java api的大牛在哪里用到了设计模式,于是重拾一下设计模式。写这篇的文章为了让自己温习一下设计模式,结合java api中的设计从设计思想中想设计模式能够更好理解设计模式。这次先从设计模式的创建型开始讲起。
我先简单得介绍一下设计模式:设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。
讲到设计模式就不得不讲设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3、依赖倒转原则(Dependence Inversion Principle)
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
5、迪米特法则,又称最少知道原则(Demeter Principle)
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。
接下来我们进入主题讲讲设计模式的实现,设计模式中有三种类型:创建型、结构型、行为型。今天我们讲的是创建形模式。创建型模式呢有:工厂模式、抽象工厂模式、原型模式、构造者模式、单例模式。
一、工厂模式
1.简述:定义一个创建对象的接口,让子类决定实例化那个一个对象,将实例化延迟到子类。解决了接口选择的问题
2角色:
Factory:创建对象的类,里面有创建对象的方法能决定创建那个一个对象。
Product:定义产品的一般行为的接口
ProductA:实现产品的具体类,工厂主要生产的对象
3.类图
4.java代码
Factory
public class Factory {
public static Product getProductA() {
return new ProductA();
}
public static Product getProductB() {
return (Product) new ProductB();
}
}
product 接口
public interface Product {
public void fun();
}
productA 实现product接口 productB同理
public class ProductA implements Product {
@Override
public void fun() {
System.out.println("I am A!");
}
}
测试类
public class Main {
public static void main(String agrs[]) {
Product p = Factory.getProductA();
p.fun();
p=Factory.getProductB();
p.fun();
}
}
结果:
我写的这个是简单的工厂模式。要实例化哪一个类由factory决定,调用不同的方法返回不同的实例化对象。在java api中有那些地方用到了工厂模式呢?我举一个例子吧 java.util.concurrent.Executor 下线程池的实例方式 线程池继承ExecutorService接口 由Executors的静态方法来创建对象 如单例线程池 Excetors.newSingletonExecutor() 返回
ps:当初有米科技的面试官就是问我工厂模式在java api设计中哪里用到的
上面我写的那个是简单的工厂模式,其实存在一个很大的问题违背了开放封闭原则,每次添加和删除抽象子类的时候,都需要对工厂类进行操作,这样不仅对工厂类的扩展开放了,还开放了工厂类的修改,这就是违背开放封闭原则的。因为按照开放封闭原则,新增加一个需求,应该是在原有类的基础上进行扩展,而不是对原有类进行修改。这样整个模式在生成新算法类时,只是进行扩展而不对模式中原有的代码进行修改,这就是符合开放封闭原则的。
所以要抽象多一层工厂出来,定义一个决定工厂一般行为的工厂接口
角色:
Factory:定义一个工厂接口
实现工厂的子类:
产品接口
产品子类
Factory 接口
public interface Factory {
public Product getProduct();
}
子工厂A
public class FactoryA implements Factory {
@Override
public Product getProduct() {
return new ProductA();
}
测试类
public class Main {
public static void main(String args[]) {
Factory f = null;
Product p = null;
f = new FactoryA();
p=f.getProduct();
p.fun();
f = new FactoryB();
p = f.getProduct();
p.fun();
}
}
}
结果
二、抽象工厂模式
1.简述:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
2类图:
3.实现:
我们将创建 Shape 和 Color 接口和实现这些接口的实体类。下一步是创建抽象工厂类 AbstractFactory。接着定义工厂类 ShapeFactory 和 ColorFactory,这两个工厂类都是扩展了 AbstractFactory。然后创建一个工厂创造器/生成器类 FactoryProducer。
AbstractFactoryPatternDemo,我们的演示类使用 FactoryProducer 来获取 AbstractFactory 对象。它将向 AbstractFactory 传递形状信息 Shape(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。同时它还向 AbstractFactory 传递颜色信息 Color(RED / GREEN / BLUE),以便获取它所需对象的类型。
结构图
shape 接口:
public interface Shape {
void draw();
}
实现shape接口
Rectangle
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("I am Rectangle");
}
}
Circle
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("I am Circle");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("I am Square");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("I am Square");
}
}
为颜色创建一个接口。
Color
public interface Color {
public void fill();
}
实现接口的子类
Bule
public class Bule implements Color {
@Override
public void fill() {
System.out.println("fill on Bule");
}
}
Green
public class Green implements Color {
@Override
public void fill() {
System.out.println("fill on Green");
}
}
Red
public class Red implements Color {
@Override
public void fill() {
System.out.println("fill on Red");
}
}
定义工厂类
为 Color 和 Shape 对象创建抽象类来获取工厂。
public abstract class AbstractFactory {
abstract Color getColor(String color);
abstract Shape getShape(String shape) ;
}
创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象
ShapeFactory
public class ShapeFactory extends AbstractFactory {
@Override
Color getColor(String color) {
return null;
}
@Override
Shape getShape(String shape) {
if(shape == null){
return null;
}
if(shape.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shape.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shape.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
ColorFactory
public class ColorFactory extends AbstractFactory {
@Override
Color getColor(String color) {
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
} else if(color.equalsIgnoreCase("GREEN")){
return new Green();
} else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
@Override
Shape getShape(String shape) {
return null;
}
}
创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
测试类
public class Main {
public static void main(String agrs[]) {
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");//获取形状工厂
Shape shape1 = shapeFactory.getShape("CIRCLE"); //获取形状为 Circle 的对象
shape1.draw();//调用 Circle 的 draw 方法
Shape shape2 = shapeFactory.getShape("RECTANGLE");//获取形状为 Rectangle 的对象
shape2.draw();//调用 Rectangle 的 draw 方法
Shape shape3 = shapeFactory.getShape("SQUARE");//获取形状为 Square 的对象
shape3.draw();//调用 Square 的 draw 方法
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR"); //获取颜色工厂
Color color1 = colorFactory.getColor("RED");//获取颜色为 Red 的对象
color1.fill();//调用 Red 的 fill 方法
Color color2 = colorFactory.getColor("Green");//获取颜色为 Green 的对象
color2.fill();//调用 Green 的 fill 方法
Color color3 = colorFactory.getColor("BLUE");//获取颜色为 Blue 的对象
color3.fill();//调用 Blue 的 fill 方法
}
}
结果:
关于抽象工厂模式在java api中呢 我好像没有找到但是我查看英语文档发现:
Abstract factory (recognizeable by creational methods returning the factory itself which in turn can be used to create another abstract/interface type)javax.xml.parsers.DocumentBuilderFactory#newInstance()
javax.xml.transform.TransformerFactory#newInstance()
javax.xml.xpath.XPathFactory#newInstance()
就是说抽血模式在java api中用到的 有 javax.xml.transform.TransformerFactory.newInstance 个人见解在 java.lang.Class.newInstance 即是反射中也有用到抽象工厂模式的设计
三构建者模式
1简述:建造者模式:将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。解决了主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
一般用于某一个部件不会变,但是组成他的部件会变
2实用范围:1、当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。2、当构造过程必须允许被构造的对象有不同表示时。
3类图:
4角色:
Builder:为创建一个产品对象的各个部件指定抽象接口。
ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。
Director:构造一个使用Builder接口的对象,指导构建过程。
Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
5.实现
创建BUilder接口 PersonBuilder
public interface PersonBuilder {
public void buildHead();
public void buildBody();
public void buildFoot();
public Person builPerson();
}
ConcreteBuilder实现builder接口
public class ManBuilder implements PersonBuilder {
private Person person;
public ManBuilder() {
person = new Person();
}
@Override
public void buildHead() {
person.setHead("建造男人的头");
}
@Override
public void buildBody() {
person.setBody("建造男人的身体");
}
@Override
public void buildFoot() {
person.setFoot("建造男人的脚");
}
@Override
public Person builPerson() {
return person;
}
}
public class WomanBuilder implements PersonBuilder {
private Person person;
public WomanBuilder() {
person=new Person();
}
@Override
public void buildHead() {
person.setHead("建造女人的头");
}
@Override
public void buildBody() {
person.setBody("建造女人的身体");
}
@Override
public void buildFoot() {
person.setFoot("建造女人的脚");
}
@Override
public Person builPerson() {
return person;
}
}
Product 创建对象的类 Person 以及其子类 man 和 woman
public class Person {
private String body;//身体
private String head;//头
private String foot;//脚
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getHead() {
return head;
}
public void setHead(String head) {
this.head = head;
}
public String getFoot() {
return foot;
}
public void setFoot(String foot) {
this.foot = foot;
}
@Override
public String toString() {
return "Person [body=" + body + ", head=" + head + ", foot=" + foot + "]";
}
}
public class Man extends Person {
public Man() {
System.out.println("建造男人开始..");
}
}
Director 指导构建过程
public class PersonDirector {
public Person constructPerson(PersonBuilder pb) {
pb.buildBody();
pb.buildFoot();
pb.buildHead();
return pb.builPerson();
}
}
测试类
public class Main {
public static void main(String agrs[]) {
PersonDirector pd = new PersonDirector();
Person man = pd.constructPerson(new ManBuilder());
Person women = pd.constructPerson(new WomanBuilder());
System.out.println(man);
System.out.println(women);
}
}
结果:
构建者模式在java api中的应用如:StringBuffer中的append() 以及StringBuilder中的append()
四、原型模式
1.用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
实质上就是定义好一个对类的模板实现Cloneable接口,实例一个对象后。以后需要这个对象不再实例化而是通过clone复制,因为使用原型模式创建对象比直接new一个对象在性能上要好的多。Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
2.注意:深拷贝与浅拷贝。Object类的clone方法只会拷贝对象中的基本的数据类型 (8种基本数据类型byte,char,short,int,long,float,double,boolean),对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。
3.类图:
4.实现
public class Prototype implements Cloneable {
public static int i;
public Prototype() {
i++;
}
public void show() {
System.out.println("建造成功");
}
@Override
public Prototype clone() {
Prototype prototype = null;
try {
prototype = (Prototype)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();}
return prototype;
}
}
测试类
public class Main {
public static void main(String args[]) {
Prototype prototype = new Prototype();
Prototype cp;
for(int i=0;i<10;i++) {cp=prototype.clone();cp.show();}
System.out.println(Prototype.i);
}
}
测试结果
嗯最后一个是单例模式........................下次讲吧 有点事先溜了
下面上传的文件是我实现代码