设计的六大原则
单一职责原则(Single Responsibility Principle)
不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
里氏替换原则(Liskov Substitution Principle)
子类可以实现父类的抽象方法,不能覆盖非抽象方法;子类可以扩展自己的方法。该原则确保父类的行为不会改变,后续有对系统做扩展时,能够保障系统的稳定性。
依赖倒置原则(Dependence Inversion Principle)
A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
B.抽象不应该依赖于具体,具体应该依赖于抽象。
接口隔离原则(Interface Segregation Principle)
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
迪米特法则(Law Of Demeter)
一个对象应该对其他对象保持最少的了解。
开闭原则(Open Close Principle)
对扩展开放,对修改关闭。
为了接近六大原则而诞生的一些设计经验 称设计模式
工厂模式
如果有许多地方都需要生成A的对象,那么你需要写很多A a=new A()。 如果需要修改的话,你要修改许多地方。 但是如果用工厂模式,你只需要修改工厂代码。其他地方引用工厂,可以做到只修改一个地方,其他代码都不动,就是解耦了。
简单工厂
public class SimpleFactory {
private static SimpleFactory simpleFactory = new SimpleFactory();
private SimpleFactory( ) {
}
public static SimpleFactory getSimpleFactory(){
return simpleFactory;
}
public Car makeCar(int strategary){
switch (strategary){
case 1:
return new BenChi();
case 2:
return new DaZong();
}
return null;
}
}
public class TestSimpleFactory {
public static void main(String[] args){
Car car = SimpleFactory.getSimpleFactory().makeCar(2);
car.run();
}
}
工厂类根据逻辑判断可以自行创建需要的对象,客户端不需要知道对象是如何创建的,只需要拿来使用就可以,分离开了创建和消费的职责;但是不利于扩展,如果要增加一个,要添加一个case,逻辑判断会越来越多,不利于维护和扩展。
工厂方法
public static void main(String[] args){
CarFactory carFactory = new BenChiFactory();
Car car = carFactory.makeCar();
car.run();
}
简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态的实例化相关的类,对于客户端来说,去除了与具体产品的依赖。当需要增加一个功能,如:求一个数的N次方 时,不但要增加相应的运算类,也要在运算工厂类的方法里加“case的分支条件”,修改原有的类,这不但对扩展开放,也对修改开放了,违背了“开放-封闭原则”。
而使用工厂方法模式,不需要修改原有的类,符合“开放-封闭原则”,但是需要修改客户端的代码,它将简单工厂的内部逻辑判断移到了客户端代码来进行。
工厂方法克服了简单工厂违背“开放-封闭原则”的缺点,又保持了封装对象创建过程的优点,降低了客户端程序与产品对象的耦合。工厂方法模式是简单工厂模式的进一步抽象和推广。
抽象工厂
package com.jack.designermodel.factory.simple.abstractfactory.abstrwithreflect;
public class MySqlFactory implements IbFactory{
@Override
public IUser createUser() {
return new MysqlUserImpl();
}
@Override
public IDepartment createDept() {
return new MysqlDeptImpl();
}
}
public class TestReflectFactory {
public static void main(String[] args) {
DBFactoryAware aware = new DBFactoryAware("com.jack.designermodel.factory.simple.abstractfactory.abstrwithreflect.MySqlFactory");
IDepartment dept = aware.createFactory().createDept();
IUser user = aware.createFactory().createUser();
dept.addDept();
user.addUser();
}
}
如果产品单一,要想达到以上的效果,合适用工厂模式;但是如果有多个品种分级时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
装饰者模式
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。对于扩展功能的情况,提供了比继承更有弹性的解决方案。
public class Client {
public static void main(String[] args) {
DarkRoast darkRoast = new DarkRoast();
Beverage beverage = null;
beverage = new Mica(darkRoast);
beverage = new Milk(beverage);
System.out.println("购买到:" + beverage.getDescription() + " 花费:" + beverage.cost());
}
}
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "darkroast coffee";
}
@Override
public double cost() {
return 5;
}
}
public abstract class CondimentDecorator extends Beverage{
Beverage beverage;
public abstract String getDescription();
}
public class Moca extends CondimentDecorator {
public Moca(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + " with moca";
}
@Override
public double cost() {
return beverage.cost() + 1.9;
}
}
public class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + " with milk !";
}
@Override
public double cost() {
return beverage.cost() + 2.1;
}
}
购买到:darkroast coffee with moca with milk ! 花费:9.0
适用性
- 需要扩展一个类的功能或给一个类增加附加责任。
- 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
- 需要增加由一些基本功能的排列组合而产生的非常大量的功能
就增加功能来说, Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。
责任链模式
遇到一次请求,处理完要经历1到n个处理阶段,每个阶段要承接上一个阶段的信息时,采用抽象出每个阶段的业务节点,采用链式的方式进行。这样做的好处是将复杂的职责单一化,可以根据需求不断的改变处节点顺序方便扩展,
public class Request {
private int type; // 0 : 请假 1:加薪
private double count;// 天数 、 加薪
private String name;
private int position;//0 职工 1 经理 2 总监 3总经理
public Request(int type, double count,String name,int position) {
this.type = type;
this.count = count;
this.name = name;
this.position = position;
}
public int getType() {
return type;
}
public double getCount() {
return count;
}
public String getName() {
return name;
}
public int getPosition() {
return position;
}
}
public interface Manager {
public void requestHandle(Request request);
}
public class ManagerImpl implements Manager {
protected Manager manager;
public void setChain(Manager manager){
this.manager = manager;
}
@Override
public void requestHandle(Request request) {
DepartmentManagerImpl departmentManager = new DepartmentManagerImpl();//部门
ChiefManagerImpl chiefManager = new ChiefManagerImpl();//总监
GeneralManagerImpl generalManager = new GeneralManagerImpl();//总经理
departmentManager.setChain(chiefManager);
chiefManager.setChain(generalManager);
if(request.getPosition() == 0){
manager = departmentManager;
}
else if(request.getPosition() == 1){
manager = chiefManager;
}
else if(request.getPosition() == 2){
manager = generalManager;
}
manager.requestHandle(request);
}
}
public class DepartmentManagerImpl extends ManagerImpl {
@Override
public void requestHandle(Request request) {
if (0 == request.getType()){
System.out.println("部门经理审批"+request.getName()+"请假事件");
if(request.getCount() <= 2){
System.out.println("部门经理审批通过," + request.getName() +"的请假申请通过!");
}else {
manager.requestHandle(request);
}
}
if (1 == request.getType()){
System.out.println("部门经理审批"+request.getName()+"调薪事件");
if(request.getCount() <= 1000){
System.out.println("部门经理审批通过," + request.getName() +"的调薪申请通过!");
}else {
manager.requestHandle(request);
}
}
}
}
public class ChiefManagerImpl extends ManagerImpl {
@Override
public void requestHandle(Request request) {
if (0 == request.getType()){
System.out.println("总监审批"+request.getName()+"请假事件");
if(request.getCount() <= 5){
System.out.println("总监审批通过," + request.getName() +"的请假申请通过!");
}else {
manager.requestHandle(request);
}
}
if (1 == request.getType()){
System.out.println("总监审批"+request.getName()+"调薪事件");
if(request.getCount() <= 3000){
System.out.println("总监审批通过," + request.getName() +"的调薪申请通过!");
}else {
manager.requestHandle(request);
}
}
}
}
public class GeneralManagerImpl extends ManagerImpl {
@Override
public void requestHandle(Request request) {
if (0 == request.getType()){
System.out.println("总经理审批"+request.getName()+"请假事件");
if(request.getCount() <= 10){
System.out.println("总经理审批通过," + request.getName() +"的请假申请通过!");
}else {
System.out.println(request.getName() + "的请假申请总经理审批不通过,请调整");
}
}
if (1 == request.getType()){
System.out.println("总经理审批"+request.getName()+"调薪事件");
if(request.getCount() <= 5000){
System.out.println("总经理审批通过," + request.getName() +"的调薪申请通过!");
}else {
System.out.println(request.getName() + "的调薪申请总经理审批不通过,请调整");
}
}
}
}
public class Employee {
public static void main(String[] args) {
Request request = new Request(0,8,"张三",0);
Manager manager = new ManagerImpl();
manager.requestHandle(request);
}
}
在客户端进行链次序调整,和上例相比,相当于抽象出一个链对象,降低具体节点和链表耦合
public class Test {
public static void main(String[] args) {
String msg = "大家好:) ,<script> <script> , 这是敏感词。";
ServletRequestt request = new ServletRequestImp(msg);
ServletRespondd response = new ServletRespondImp();
Filterr fc1 = new CodeFilter();
Filterr fc2 = new FaceFilter();
Filterr fc3 = new HtmlFilter();
FilterChainn fc = new SpecificFilterChain();
fc.addFilter(fc1);
fc.addFilter(fc2);
fc.addFilter(fc3);
fc.doFilter(request,response,fc);
System.out.println("final request : " + request.getContent());
System.out.println("final respond : " + response.printResponse());
}
}
public class SpecificFilterChain implements FilterChainn {
private ArrayList<Filterr> filters = new ArrayList<>();
private int index = 0;
public FilterChainn addFilter(Filterr filter){
filters.add(filter);
return this;
}
@Override
public void doFilter(ServletRequestt servletRequestt, ServletRespondd servletRespondd, FilterChainn filterChainn) {
if(index == filters.size()) return;
Filterr filter = filters.get(index);
index++;
filter.init();
filter.doFilter(servletRequestt, servletRespondd, filterChainn);
filter.destory();
}
}
责任链问题:在找到正确的处理对象之前,所有的条件判定都要执行一遍,当责任链过长时,可能会引起性能的问题,如果某个节点耗时过长,会导致后面的业务阻塞。类递归操作,出错不易排查。
如果一个类的业务逻辑存在过多if-else或者一个审核需要多级审批才能走完,可以采用责任链来进行改造。
适配器模式
适配器模式让那些接口不兼容的类可以一起工作。可以作为类结构型模式,也可以作为对象结构型模式。在适配器模式定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。
类适配
public class VolatgeAdapter extends Voltage220 implements Voltage5 {
@Override
public int out() {
int v = super.out220();
System.out.println("适配器开始工作");
int vd = v /44;
System.out.println("适配后的电压:" + vd);
return vd;
}
}
public class Voltage220 {
public int out220(){
System.out.println("插座输出电压 220v");
return 220;
}
}
对象适配
不继承src类,而是持有src类的实例,以解决兼容性的问题。根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。
public class VolatgeAdapter implements Voltage5 {
Voltage220 voltage220;
public VolatgeAdapter(Voltage220 voltage220) {
this.voltage220 = voltage220;
}
@Override
public int out() {
int v = voltage220.out220();
System.out.println("适配器开始工作");
int vd = v /44;
System.out.println("适配后的电压:" + vd);
return vd;
}
}
日常使用这个的频率应该是非常高的。
构造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,允许用户可以只通过指定复杂对象的类型和内容就可以构建它们
public class Client {
//客户针对boss进行
public static void main(String[] args) {
Boss boss = new Boss();
Computer computer = boss.commandAssembleToGetComputer(new NormalAssemblyOperator());
System.out.println("我的一般电脑配置如下:");
System.out.println(computer.toString());
Computer computer1 = boss.commandAssembleToGetComputer(new SuperAssemblyOperator());
System.out.println("我的高级电脑配置如下:");
System.out.println(computer1.toString());
}
}
当然可以把new 通过读取配置,反射动态创建operator,老板指挥的不同operator构建不同配置的电脑
使用建造者模式可以使客户端不必知道产品内部的组成细节。(封装性)
具体的建造者之间是相互独立的,对系统的扩展非常有利。(扩展性)
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制;如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
桥接模式
用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
假设有一座桥,桥左边为A,桥右边为B,A有A1,A2,A3等,表示桥左边的三个不同地方,B有B1,B2,B3等,表示桥右边的三个不同地方,假设我们要从桥左侧A出发到桥的右侧B,我们可以有多重方案,A1到B1,A1到B2,A1到B3,A2到B1...等等
此处抽象化与实现化分别指代实例中的双方,而且实现化对应目的地方(通过实现桥接口进行扩展),抽象方对应来源地方(通过继承抽象类来进行扩展),如果我们不使用桥接模式,我们会怎么想实现这个实例呢?很简单,我们分别定义来源地A1、A2、A3类和目的地B1、B2、B3,然后具体的实现就是,A1到B1一个类,A1到B2一个类,等,如果我们要扩展了A和B ,要直接增加An类和Bn类,如此编写不说类内部重复性代码多,而且还会导致类结构的急剧膨胀,最重要的是,在通过继承实现路径的时候,会造成双方耦合性增大,而这又进一步加剧了扩展的复杂性。使用桥结构模式可以很好地规避这些问题:重在解耦。
public class Client {
public static void main(String[] args) {
Phone phone1 = new Apple();//A1
phone1.setPhoneSoft(new GameSoft());//B1
phone1.phoneRun();//A1 - B1
phone1.setPhoneSoft(new AddressSoft());//B2
phone1.phoneRun();//A1 - B2
Phone phone2 = new Nokia();//A2
phone2.setPhoneSoft(new AddressSoft());//B2
phone2.phoneRun();
}
}
迭代模式
提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。主要是聚合对象创建迭代器,借助单一职责的原则,实现客户端可以对聚合的各种对象实现相同的操作,达到代码复用的效果。
public abstract class Interate {
public abstract Object first();
public abstract Object next();
public abstract boolean isDone();
public abstract Object currentItem();
}
public class ConcreteInterate extends Interate {
private ArrayListA lista;
private int current = 0;
public ConcreteInterate(ArrayListA list) {
this.lista = list;
}
@Override
public Object first() {
return lista.getItem(0);
}
@Override
public Object next() {
current ++ ;
return lista.getItem(current);
}
@Override
public boolean isDone() {
return current != lista.count();
}
@Override
public Object currentItem() {
return lista.getItem(current);
}
}
public abstract class ListA {
public abstract Interate interate();
}
public class ArrayListA extends ListA {
private List<Object> items = new ArrayList<>();
@Override
public Interate interate() {
return new ConcreteInterate(this);
}
public int count(){
return items.size();
}
public void addObject(Object object){
items.add(object);
}
public Object getItem(int index){
return items.get(index);
}
}
public class Test {
public static void main(String[] args) {
//创建数组
ArrayListA arrayListA = new ArrayListA();
arrayListA.addObject(1);
arrayListA.addObject(33);
arrayListA.addObject("mamabi");
arrayListA.addObject("222");
Interate interate = arrayListA.createInterate();
Object o = interate.first();
while (! interate.isDone()){
//
System.out.println(o);
o = interate.next();
}
}
}
观察者模式
在对象之间定义了一对多的关系,这样一来,当一个对象改变状态,和它相关的对象会收到通知并自动更新。
public interface Observe {
public void callSell();
public void callBuy();
public void callWait();
}
public interface Agent {
public void add(Observe observe);
public void remove(Observe observe);
public void notifyObserve();
}
public class ClientTwo implements Observe {
@Override
public void callSell() {
System.out.println("two house can sell");
}
@Override
public void callBuy() {
System.out.println("two house can buy");
}
@Override
public void callWait() {
System.out.println("two house should wait to deal");
}
}
public class ClientOne implements Observe{
@Override
public void callSell() {
System.out.println("one house can sell now");
}
@Override
public void callBuy() {
System.out.println("one house can buy now");
}
@Override
public void callWait() {
System.out.println("one house should wait to deal");
}
}
public class Manager implements Agent{
private List<Observe> observes;
private int houseStatus;
public Manager() {
this.observes = new ArrayList<>();
}
@Override
public void add(Observe observe) {
observes.add(observe);
}
@Override
public void remove(Observe observe) {
if (! observes.isEmpty()){
observes.remove(observe);
}
}
public void setHouseStatus(int status){
houseStatus = status;
}
@Override
public void notifyObserve() {
for (int i = 0 ; i < observes.size();i++){
if(houseStatus == 0)
observes.get(i).callWait();
if(houseStatus == 1)
observes.get(i).callBuy();
if(houseStatus == 2)
observes.get(i).callSell();
}
}
}
public class AbstrObserveTest {
//观察者创建
public static void main(String[] args) {
Observe observe2 = new ClientTwo();
Observe observe1 = new ClientOne();
Agent agent = new Manager();
agent.add(observe1);
agent.add(observe2);
((Manager) agent).setHouseStatus(2);
agent.notifyObserve();
}
}
- 这个模式是松偶合的。改变主题或观察者中的一方,另一方不会受到影像。
代理模式
代理模式这种设计模式是一种使用代理对象来执行目标对象的方法并在代理对象中增强目标对象方法的一种设计模式。
静态代理
静态代理就是写死了在代理对象中执行这个方法前后执行添加功能的形式,每次要在接口中添加一个新方法,则需要在目标对象中实现这个方法,并且在代理对象中实现相应的代理方法,幸而Java有独特的反射技术,可以实现动态代理。
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl开始保存");
}
}
public class UserDaoProxy implements UserDao {
UserDao userDao;
public UserDaoProxy(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
System.out.println("静态代理开始");
userDao.save();
System.out.println("静态代理结束");
}
}
public class Testjing {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
userDaoProxy.save();
}
}
动态代理
Jdk的动态代理,是使用反射技术获得类的加载器并且创建实例,根据类执行的方法在执行方法的前后发送通知。
在代理对象Proxy的新建代理实例方法中,必须要获得类的加载器、类所实现的接口、还有一个拦截方法的句柄。
在句柄的invoke中如果不调用method.invoke则方法不会执行。在invoke前后添加通知,就是对原有类进行功能扩展了。
创建好代理对象之后,proxy可以调用接口中定义的所有方法,因为它们实现了同一个接口,并且接口的方法实现类的加载器已经被反射框架获取到了。
public class TestjckDy {
public static void main(String[] args) {
UserDao userdao = new UserDaoImpl();
System.out.println(userdao.getClass().toString());
userdao.save();
UserDao userDaoProxy = (UserDao) new ProxyFactory(userdao).getProxy();
System.out.println(userDaoProxy.getClass().toString());
userDaoProxy.save();
}
// 代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
}
public class ProxyFactory {
Object object;
public ProxyFactory(Object object) {
this.object = object;
}
public Object getProxy(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("事务开启");
Object returnValue = method.invoke(object,args);
System.out.println("事务提交");
return returnValue;
}
});
}
}
但是碰到去代理没有实现接口的对象,上面的方法就会造成冗余接口的情况。下边采用cglib的方式进行。
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyFactory implements MethodInterceptor {
private Object target;
public CglibProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] arges, MethodProxy methodProxy) throws Throwable {
System.out.println("事务开始");
Object returnValue = method.invoke(target,arges);
System.out.println("事务结束");
return returnValue;
}
}
public class UserDao {
public void save(){
System.out.println("无接口保存");
}
}
public class ProductDao {
public void save(){
System.out.println("保存商品");
}
}
public class TestCglibTest {
public static void main(String [] args)
{
CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(new UserDao());
UserDao userDao = (UserDao) cglibProxyFactory.getProxyInstance();
userDao.save();
ProductDao productDao = (ProductDao) new CglibProxyFactory2(new ProductDao()).getProxyInstance();
productDao.save();
}
}
Cglib实现代理的方式是和目标对象使用同一个父类,无论是继承还是实现接口,都是为了代理对象能直接调用目标对象的方法。
策略模式
策略模式定义了一系列的算法,并将每一个算法封装起来,使每个算法可以相互替代,使算法本身和使用算法的客户端分割开来,相互独立。