java程序的设计原则

6大原则:

单一职责:一个类和方法只做一件事。
开闭原则:对修改关闭,对扩展开发。
里氏替换原则:使用任意的子类替换当前子类,方法调用的行为不会发生变化。
依赖倒置:依赖于抽象,而非具体实现,即面向接口编程(如方法参数,类属性使用接口声明,这样可接收任何子类)。
接口隔离:使用多个隔离的接口定义抽象,降低耦合。
最少知道/迪米特原则:降低类之间的依赖,聚合,组合等。

1:简单工厂设计模式

简单工厂模式并不是Gof23种设计模式中的一种,但也是一种设计模式废话,而且在实际工作中用的还是比较多的,所以从实用性角度来说,比较重要,有必要学习一下。

当对象创建比较复杂时,可以考虑使用简单工厂设计模式,简化客户端创建对象的复杂度,以及降低对象本身发生变化导致对象创建方式发生变对客户端的影响时也可以考虑使用简单工厂设计模式。

简单工厂模式的UML图如下:

在这里插入图片描述

下面看下如何将其翻译为具体的程序代码。

源码 。

1.1:Product

public interface Product {
    void show();
}

1.2:三个ConcreteProduct

public class ConcreteProduct1 implements Product {
    @Override
    public void show() {
        System.out.println("一号产品显示。。。");
    }
}
public class ConcreteProduct2 implements Product {
    @Override
    public void show() {
        System.out.println("二号产品显示。。。");
    }
}
public class ConcreteProduct3 implements Product {
    @Override
    public void show() {
        System.out.println("三号产品显示。。。");
    }
}

1.3:工厂类

public class SimpleFactory {
    static final int PRODUCT_A = 1;
    static final int PRODUCT_B = 2;
    static final int PRODUCT_C = 3;

    public static Product makeProduct(int kind) {
        if (kind == PRODUCT_A) return new ConcreteProduct1();
        if (kind == PRODUCT_B) return new ConcreteProduct2();
        if (kind == PRODUCT_C) return new ConcreteProduct3();
        return null;
    }
}

1.4:客户端

public class Client {
    public static void main(String[] args) {
        SimpleFactory.makeProduct(1).show();
        SimpleFactory.makeProduct(2).show();
        SimpleFactory.makeProduct(3).show();
    }
}

运行:

一号产品显示。。。
二号产品显示。。。
三号产品显示。。。

1.5:优化

如果我们现在要增加四号产品,如下:

public class ConcreteProduct4 implements Product {
    @Override
    public void show() {
        System.out.println("四号产品显示。。。");
    }
}

则需要修改工厂类如下只保留新增代码:

public class SimpleFactory {
    // ...
    static final int PRODUCT_D = 4;

    public static Product makeProduct(int kind) {
        // ...
        if (kind == PRODUCT_D) return new ConcreteProduct4();
        return null;
    }
}

产品类本身添加没有任何问题,因为添加的完全是全新类,但是修改工厂类明显不符合开闭原则,下面我们通过SPI 修改代码以满足开闭原则。

改造源码 。

首先创建META-INF\services\dongshi.daddy.simplefactory.spi.Product,输入如下内容:

dongshi.daddy.simplefactory.spi.ConcreteProduct1
dongshi.daddy.simplefactory.spi.ConcreteProduct2
dongshi.daddy.simplefactory.spi.ConcreteProduct3

然后定义如下注解,用来唯一标识对象的key:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Key {
    int id();
}

然后修改工厂类分别使用@Key注解设置其id值,如下:

@Key(id = 1)
public class ConcreteProduct1 implements Product {}
@Key(id = 2)
public class ConcreteProduct2 implements Product {}
@Key(id = 3)
public class ConcreteProduct3 implements Product {}

最后修改工厂类如下:

public class SimpleFactory {
    /*static final int PRODUCT_A = 1;
    static final int PRODUCT_B = 2;
    static final int PRODUCT_C = 3;
    static final int PRODUCT_D = 4;*/
    private static Map<Integer, Product> productMap = new HashMap<>();

    static {
        ServiceLoader<Product> load = ServiceLoader.load(Product.class);
        Iterator<Product> iterator = load.iterator();
        while (iterator.hasNext()) {
            Product next = iterator.next();
            int id = next.getClass().getAnnotation(Key.class).id();
            productMap.put(id, next);
        }
    }

    public static Product makeProduct(int kind) {
        /*if (kind == PRODUCT_A) return new ConcreteProduct1();
        if (kind == PRODUCT_B) return new ConcreteProduct2();
        if (kind == PRODUCT_C) return new ConcreteProduct3();
        if (kind == PRODUCT_D) return new ConcreteProduct4();*/
        return productMap.get(kind);
    }
}

这样当我们增加一个新的产品类时只需要增加对应的类并使用@Key注解设置其id,然后将其类全限定名称设置到spi配置文件中就可以了。

写在后面

当你只有一类对象需要创建时,可以使用简单工厂设计模式,但是虽然我们通过SPI解决了同一类对象增加新的对象类型时需要修改工厂类代码的问题,却无法解决增加新的对象类型时需要修改工厂类的问题(因为是新的顶层接口定义,所以SPI无法解决),这明显就违背了面向对象设计模式SOLID中的O,open close principle,开闭原则,这个问题我们需要通过其他设计模式来解决,比如工厂设计模式。

参考文章列表

简单工厂模式 。

更多推荐