首页 文章 精选 留言 我的

精选列表

搜索[前端设计],共10000篇文章
优秀的个人博客,低调大师

设计模式学习---单例模式

单例模式---对于整个系统只需要一个实体就能完成工作的情况下,我们系统只需要一个实体并且保证只有一个实例,避免造成资源浪费 1.懒汉 懒汉模式是在需要用到该实例的时候才进行实例化 优点:节约资源,在需要用到该实例的时候才初始化 缺点:线程非安全,并发访问情况下,有可能多次实例化,并且每次实例化都覆盖上一次的实例 public class Singleton { private static Singleton SINGLETON; private Singleton(){} public static Singleton getInstance(){ if(Singleton.SINGLETON == null); Singleton.SINGLETON = new Singleton(); return SINGLETON; } } 2.饿汉 饿汉单例模式在类加载的时候就实例化 优点:安全,不存在并发创建多实例问题 缺点:容易造成资源浪费,一直占用着资源且无法回收 public class Singleton { private static final Singleton SINGLETON = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return SINGLETON; } } 3.懒汉模式(方法加锁) 这种模式在获取实例的时候添加synchronize同步锁能避免多并发情况下造成创建多实例问题 优点:具有懒汉模式的节约资源优点,且方法加锁情况下避免了多并发创建多次实例的情况 确定:方法锁消耗性能比较大,必须是第一访问完整个方法才到第二次访问进入 public class Singleton { private static Singleton SINGLETON; private Singleton(){} public synchronized static Singleton getInstance(){ if(Singleton.SINGLETON == null); Singleton.SINGLETON = new Singleton(); return SINGLETON; } } 4.双重锁校验(推荐) 双重锁校验是优化了方发锁的方式而来,优化啊了多并发情况下性能低下的结果 优点:保证了线程安全情况下,节约资源且访问性能高 public class Singleton { private static Singleton SINGLETON; private Singleton(){} public static Singleton getInstance(){ if(Singleton.SINGLETON == null){ synchronized (Singleton.class) { if(Singleton.SINGLETON == null) { Singleton.SINGLETON = new Singleton(); } } } return SINGLETON; } } 进入方法体之后首先判断了实例是否存在,如果存在,则直接返回实例,否则加锁执行多一次判断,如果为null再实例化。因为第一次判断和加锁之间,对象可能已经实例化,所以加锁之后再判断一次,避免多次创建。但是这种方式还有点缺陷,synchronized关键字可以保证多线程情况下同步问题,如果是多核计算机(现在绝大部分都是多核计算机)情况下,还会有一个指令重排的问题所以我们需要用volatile 来修饰SINGLETON,最后改造成下面代码 public class Singleton { private volatile static Singleton SINGLETON; private Singleton(){} public static Singleton getInstance(){ if(Singleton.SINGLETON == null){ synchronized (Singleton.class) { if(Singleton.SINGLETON == null) { Singleton.SINGLETON = new Singleton(); } } } return SINGLETON; } } 5.静态内部类 静态内部类是在调用的时候才会进行加载,是懒汉模式另外一种实现方式 public class Singleton { private Singleton(){} public static Singleton getInstance(){ return Instance.singleton; } private static class Instance{ private static final Singleton singleton = new Singleton(); } } 6.枚举 枚举为最优的单例模式实现方案,因为可以防反射暴力创建对象,也可以避免序列化问题,下面先放了一个简单的例子, public enum SingletonEnum { SINGLETON; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public static SingletonEnum getInstance(){ return SINGLETON; } } 看一下使用方式 public static void main(String[] args) { SingletonEnum.SINGLETON.setName("name1"); System.out.println(SingletonEnum.SINGLETON.getName()); } 输出结果,由此可见SingletonEnum.SINGLETON 时调用的都是同一个实例 下面我们看看枚举类型防放射暴力创建实例 我们用之前静态内部类的那个代码来比较 public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 反射获取构造器 Constructor<Singleton> singletonConstructor = Singleton.class.getDeclaredConstructor(); // 通过构造器创建对象 Singleton singleton1 = singletonConstructor.newInstance(); // 通过我们单例获取实例的接口获取实例 Singleton singleton2 = Singleton.getInstance(); // 下面结果为false,证明是2个不一样的实例,甚至都不用调用构造器的 setAccessible() 就能成功新建一个实例 System.out.println(singleton1 == singleton2); } 接下来再看看枚举 public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 反射获取构造器 Constructor<SingletonEnum> singletonEnumConstructor = SingletonEnum.class.getDeclaredConstructor(); // 通过构造器创建对象 SingletonEnum singletonEnum1 = singletonEnumConstructor.newInstance(); // 获取单例 SingletonEnum singletonEnum2 = SingletonEnum.SINGLETON; // 下面结果为false,证明是2个不一样的实例,甚至都不用调用构造器的 setAccessible() 就能成功新建一个实例 System.out.println(singletonEnum1 == singletonEnum2); } 这时候报是报了个java.lang.NoSuchMethodException,原因是因为枚举类型没有无参构造 下面我们进入debug模式可以看到只有一个带一个String参数和一个int参数的构造方法 所以改造成 public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 反射获取构造器 Constructor<SingletonEnum> singletonEnumConstructor = SingletonEnum.class.getDeclaredConstructor(String.class,int.class); // 通过构造器创建对象 SingletonEnum singletonEnum1 = singletonEnumConstructor.newInstance("",1); // 获取单例 SingletonEnum singletonEnum2 = SingletonEnum.SINGLETON; // 下面结果为false,证明是2个不一样的实例,甚至都不用调用构造器的 setAccessible() 就能成功新建一个实例 System.out.println(singletonEnum1 == singletonEnum2); } 但是改过来之后报了个 java.lang.IllegalAccessException 非法访问异常 原因是如果实例化的对象是个枚举类型,就会抛出这个异常,这说明枚举类型天生就是单例的 public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, null, modifiers); } } if ((clazz.getModifiers() & Modifier.ENUM) != 0) throw new IllegalArgumentException("Cannot reflectively create enum objects"); ConstructorAccessor ca = constructorAccessor; // read volatile if (ca == null) { ca = acquireConstructorAccessor(); } @SuppressWarnings("unchecked") T inst = (T) ca.newInstance(initargs); return inst; } if ((clazz.getModifiers() & Modifier.ENUM) != 0) throw new IllegalArgumentException("Cannot reflectively create enum objects"); 序列化与反序列化,如果我们实体需要储存到程序以外的存储媒介,当再次获取时候,这个实例并非我们最开始的实例 序列化的时候实体类必须实现Serializable public class Singleton implements Serializable{} public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { // 通过获取实例接口获取实例 Singleton singleton1 = Singleton.getInstance(); // 创建输出流并且输出到文件 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\singleton\\singleton.txt")); oos.writeObject(singleton1); // 创建输入流并且反序列化实例 ObjectInputStream ios = new ObjectInputStream(new FileInputStream("D:\\singleton\\singleton.txt")); Singleton singleton2 = (Singleton) ios.readObject(); oos.close(); ios.close(); System.out.println(singleton1 == singleton2); } 序列化前后的对象结果对比,不是同一个实例 再看看枚举类型 public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { SingletonEnum singletonEnum1 = SingletonEnum.SINGLETON; // 创建输出流并且输出到文件 ObjectOutputStream oosE = new ObjectOutputStream(new FileOutputStream("D:\\singleton\\singletonE.txt")); oosE.writeObject(singletonEnum1); // 创建输入流并且反序列化实例 ObjectInputStream iosE = new ObjectInputStream(new FileInputStream("D:\\singleton\\singletonE.txt")); SingletonEnum singletonEnum2 = (SingletonEnum) iosE.readObject(); oosE.close(); iosE.close(); System.out.println(singletonEnum1 == singletonEnum2); } 序列化前后的对象是一致的,没有被破坏 所以单例的最优方案是枚举,其他方法都会因为反射或者序列化破坏了整个系统只有一个实例的原则,当然根据业务要求选择一种比较合适目前开发团队的方案也很重要

优秀的个人博客,低调大师

SAP CRM Relationship API设计原理

Unlike settype, relationship does not have a dedicated read function module maintained in its metadata table. Instead, the generic read function module COM_IL_DB_READ is used. Below is a simple explanation about each parameter of FM COM_IL_DB_READ, using read on relationship PRDCPN for example. IV_RELTYPE PRDCPN - relationship name IV_ATTR_TYPE COMT_IL_PRDCPN_ATTR_TYPE - contains relationship specific business data, in this example, the customer product id is stored in field PRID_VENDOR IT_LINK_IDENTS sourceguid or destiguid contains product guid. This will be used by the generic read API to select against DB table using OPEN SQL. The exporting parameter: ET_INTERLINKAGE - relationship header data - generic data ET_IL_ATTR Relationship specific data, in this example, PRID_VENDOR, stores the detail value. Approach1 If we can enhance COM_IL_DB_READ, we then redirect the read from CRM relationship storage table to S4 relationship storage table.Since it is not allowed to enhance SAP_ABA function module, we have to consider CDS view redirect.Further research is needed here: compare the structure of both storage table in CRM and S4 and evaluate whether view direct is feasible or not. Approach2 Since we can only make changes on BBPCRM, we have to copy the whole implementation which are in SAP_ABAP listed below into new function & subroutine, make needed changes ( table redirect ) and let FORM UI_GETDETAIL call those new implementations. This approach takes huge effort. 本文来自云栖社区合作伙伴“汪子熙”,了解相关信息可以关注微信公众号"汪子熙"。

优秀的个人博客,低调大师

python设计模式(十六):命令模式

“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern) 命令模式应该有一下几个角色: Command: 定义命令的接口,声明执行的方法,可以理解为一个基类。 ConcreteCommand: 命令接口实现对象,通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。 Receiver: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。 Invoker: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象,相当于使用命令对象的入口。 Client: 创建具体的命令对象,组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。 示例code: #-*-coding:utf-8-*-classCommand: """声明命令模式接口""" def__init__(self,obj): self.obj=obj defexecute(self): passclassConcreteCommand(Command): """实现命令模式接口""" defexecute(self): self.obj.run()classInvoker: """接受命令并执行命令的接口""" def__init__(self): self._commands=[] defadd_command(self,cmd): self._commands.append(cmd) defremove_command(self,cmd): self._commands.remove(cmd) defrun_command(self): forcmdinself._commands: cmd.execute()classReceiver: """具体动作""" def__init__(self,word): self.word=word defrun(self): print(self.word)defclient(): """装配者""" test=Invoker() cmd1=ConcreteCommand(Receiver('命令一')) test.add_command(cmd1) cmd2=ConcreteCommand(Receiver('命令二')) test.add_command(cmd2) cmd3=ConcreteCommand(Receiver('命令三')) test.add_command(cmd3) test.run_command()if__name__=='__main__': client() -------------------------- 命令一 命令二 命令三 命令模式的几个核心角色及其分工: Command(命令基类):主要声明抽象命令类的接口 ConcreteCommand(命令实现):复写基类中声明的接口,实现具体的调用功能 Receiver(命令的内容):具体执行动作的对象 Invoker(命令调度和执行):全部命令的执行和调度入口 Client(命令装配者):创建具体的命令对象,组装命令对象和接收者

优秀的个人博客,低调大师

python设计模式(七):组合模式

组合,将对象组合成树状结构,来表示业务逻辑上的[部分-整体]层次,这种组合使单个对象和组合对象的使用方法一样。 如描述一家公司的层次结构,那么我们用办公室来表示节点,则总经理办公司是根节点,下面分别由人事办公室、业务办公室、生产办公室、财务办公室,每个办公室下面可以还有跟小的办公室,每个办公室都有职责、人员数、人员薪资等属性; 上面描述是逻辑上的描述,用程序如何来实现?看下面代码: classComponentBases: """部门抽象出来的基类""" def__init__(self,name): slef.name=name defadd(self,obj): pass defremove(self,obj): pass defdisplay(self,number): passclassNode(ComponentBases): def__init__(self,name,duty): self.name=name self.duty=duty self.children=[] defadd(self,obj): self.children.append(obj) defremove(self,obj): self.children.remove(obj) defdisplay(self,number=1): print("部门:{}级别:{}职责:{}".format(self.name,number,self.duty)) n=number+1 forobjinself.children: obj.display(n)if__name__=='__main__': root=Node("总经理办公室","总负责人") node1=Node("财务部门","公司财务管理") root.add(node1) node2=Node("业务部门","销售产品") root.add(node2) node3=Node("生产部门","生产产品") root.add(node3) node4=Node("销售事业一部门","A产品销售") node2.add(node4) node5=Node("销售事业二部门","B产品销售") node2.add(node5) root.display() ----------输出----------- 部门:总经理办公室级别:1职责:总负责人 部门:财务部门级别:2职责:公司财务管理 部门:业务部门级别:2职责:销售产品 部门:销售事业一部门级别:3职责:A产品销售 部门:销售事业二部门级别:3职责:B产品销售 部门:生产部门级别:2职责:生产产品 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 "组合对象" 的含义。 ------------------------------

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册