当前位置:网站首页>Sharing ideas for a quick switch to an underlying implementation
Sharing ideas for a quick switch to an underlying implementation
2022-06-26 14:36:00 【Liziti】
High quality resource sharing
| Learning route guidance ( Click unlock ) | Knowledge orientation | Crowd positioning |
|---|---|---|
| 🧡 Python Actual wechat ordering applet 🧡 | Progressive class | This course is python flask+ Perfect combination of wechat applet , From the deployment of Tencent to the launch of the project , Create a full stack ordering system . |
| Python Quantitative trading practice | beginner | Take you hand in hand to create an easy to expand 、 More secure 、 More efficient quantitative trading system |
| Catalog |
- 1. Fast access to new implementations 1: abstract class
- 2. Solve the problems caused by simple abstraction
- 3. A more perfect scheme : Different implementations based on interfaces
The real scene is often like this , We respond to a need , There will soon be a solution , Then, a good implementation is made according to the requirements . Because the function is realized , The business is very happy, The boss is happy ,all the world is beatiful.
But with the development of the company , Someone has implemented an underlying set of standard components , As required, you have to access his , His function is similar to yours , But you have to switch to that . Regardless of the quality of its implementation , But he certainly has some advantages , But as a standard kit , It can't be completely consistent with your needs . therefore , This must involve the problem of transformation .
In this case , We are not willing to take it , After all, the code is running well , Who wants to move ? And how other people achieve , Not tested yet , Rash access , It may bring a larger pot .( from 0 To 1 Nobody cares about accuracy , But from 1 TripAdvisor 1.1 Someone will pay attention to accuracy , In other words, this is called compatibility )
however , Often under pressure , We have to answer again .
At this time, we have two ways , One is to directly change the code to someone else . This treatment is simple and rough , And there are no worries . however , And then , Is a large-scale regression test , And some points that may not be tested , Means code rollback . For some places where online operation and maintenance is more convenient , Maybe we can do this . But this is not the recommended practice in this article , No more discussion .
A more prudent approach , It should be in the case of maintaining the existing implementation , Make the newly realized access , At least you can compare . Advance and attack , Retreat and defend .
Return to the top ### 1. Fast access to new implementations 1: abstract class
Since we dare not directly replace the existing implementation , Then you have to keep two implementations , So you can use abstract classes , While maintaining the original implementation , Cut into new implementations . It's an intuitive idea , The specific implementation is as follows :
1. Abstract a public class
public abstract class AbstractRedisOperate {
private AbstractRedisOperate impl;
public AbstractRedisOperate() {
String strategy = "a"; // from config
if("a".equals(strategy)) {
impl = new RedisOperateA1Imp();
}
else {
impl = new RedisOperateB2Imp();
}
}
// Example operation interface
public void set(String key, String value);
}
- Implement two concrete classes
// Realization 1, Completely dependent on abstract class implementation ( Old functions )
public class RedisOperateOldImp extends AbstractRedisOperate {
}
// Realization 2, Implementation of new access
public class RedisOperateB2Imp extends AbstractRedisOperate {
@Override
public void set(String key, String value) {
System.out.println("this is b's implement...");
}
}
- Keep the original implementation class entry , Turn its implementation into a facade class or an adapter class
// Loading entry
@Service
public class RedisOperateFacade extends AbstractRedisOperate {
public RedisOperateFacade() {
// case1. Leave it directly to the parent class
super();
}
@Override
public void set(String key, String value) {
// fake impl
}
}
What are the benefits of the above implementation ? First , Existing implementations are pulled away , And it was preserved without any changes . The new implementation class implements a new . Through a common changeover switch , Perform switching processing . thus , It can ensure the access to the new implementation , It also retains the old implementation , In the event of an unknown failure , Can be implemented by failback .
What is the problem with the above implementation ?
When we run the code above , I found the wrong report , Why? ? Because there is a dead circle . Although we only loaded one Facade The implementation of the , But in calling super when ,super The concrete implementation will be loaded in turn , The concrete implementation will load the abstract classes super, And so on and so on , Until the stack overflows . Also known as the emergence of a dead cycle .
Return to the top ### 2. Solve the problems caused by simple abstraction
In the previous section, we already knew why the loading failed , In fact, it is a circular dependency problem . How to solve it ?
It's simply moving the code , Don't put judgment in the default constructor , Handled by a concrete appearance class , The loading policy is determined by the appearance class , Instead of concrete implementation classes or abstract classes .
The specific operation is as follows :
// 1. Appearance class controls loading
@Service
public class RedisOperateFacade extends AbstractRedisOperate {
public RedisOperateFacade() {
// case1. Leave it directly to the parent class
// super();
// case2. Decide which implementation to load
String strategy = "a"; // from config center
if("a".equals(strategy)) {
setImpl(new RedisOperateOldImp());
}
else {
setImpl(new RedisOperateB2Imp());
}
}
}
// 2. Each implementation keeps itself still
public class RedisOperateOldImp extends AbstractRedisOperate {
// old impl...
}
public class RedisOperateB2Imp extends AbstractRedisOperate {
// new impl...
@Override
public void set(String key, String value) {
System.out.println("this is b's implement...");
}
}
// 3. Abstract classes are no longer subject to load policy processing
public abstract class AbstractRedisOperate {
// Hold concrete realization
private AbstractRedisOperate impl;
public AbstractRedisOperate() {
}
protected void setImpl(AbstractRedisOperate impl) {
this.impl = impl;
}
// Example operation interface , old impl...
public abstract void set(String key, String value);
}
Made minor changes , Transfer the loading policy from the abstract class to the appearance class , The correct loading effect can be achieved . actually , For the sake of simplicity , We can even make the original implementation complete copy Into abstract classes , And a new original implementation class , You don't have to do anything , Just add an empty inheritance abstract class . And the new implementation , Then it is enough to completely cover the existing concrete implementation . So as to achieve a minimum change , And smoothly access a newly implemented effect .
But if it depends on the concrete implementation of the abstract class , There's a problem , That is, if our subclasses are not well implemented , For example, when some implementations are omitted , The code itself does not give an error message . This brings us potential risks , Because that would turn into , Part is the old implementation , The other part is the new implementation . There may be two problems : One is that one of the two implementations reports an error and the other is normal ; Second, rollback cannot be switched normally , The two implementations are coupled together .
Return to the top ### 3. A more perfect scheme : Different implementations based on interfaces
What shall I do? ? We can abstract another layer of interfaces , Each implementation deals with the interface , Only the appearance class inherits the abstract class , And the abstract class also implements the interface definition . In this case , This ensures the integrity of each implementation , And the uniformity of appearance classes . here , I take advantage of the mandatory nature of grammar , That is, the semantics of the interface must be implemented , Ensure the accuracy of the code .( Yes, of course , All the real scenes , Interfaces must have corresponding implementations , Because only interfaces are visible from the outside , If not, it must be illegal )
The specific implementation is as follows :
//1. Unified interface definition
public interface UnifiedRedisOperate {
void set(String key, String value, int ttl);
// more interface definitions...
}
// 2. Each sub implementation class
public class RedisOperateOldImp implements UnifiedRedisOperate {
@Override
public void set(String key, String value) {
System.out.println("this is a's implement...");
}
}
public class RedisOperateB2Imp implements UnifiedRedisOperate {
@Override
public void set(String key, String value) {
System.out.println("this is b's implement...");
}
}
// 3. Implementation of appearance class
@Service
public class RedisOperateFacade extends AbstractRedisOperate {
public RedisOperateFacade() {
// case1. Leave it directly to the parent class
// super();
// case2. Appearance class controls loading
String strategy = "a"; // from config center
if("a".equals(strategy)) {
setImpl(new RedisOperateOldImp());
}
else {
setImpl(new RedisOperateB2Imp());
}
}
}
public abstract class AbstractRedisOperate implements UnifiedRedisOperate {
private UnifiedRedisOperate impl;
protected void setImpl(UnifiedRedisOperate impl) {
this.impl = impl;
}
// Interface delegation
public void set(String key, String value) {
impl.set(key, value);
}
// more delegates...
}
It seems that an additional interface class has been added , But actually the whole code is much clearer and easier to read . actually , A good design , Initially, it should also be based on interfaces ( Interface oriented programming ), Here we re abstract an interface class , In fact, it is to make up for the shortcomings of the previous design , It is also a kind of refactoring . All implementations are based on interfaces , None of them can be less , Thus reducing the probability of error .
such , We can safely switch production .
The article was originally published on wechat official account : A quick switch to a low-level implementation of ideas to share
边栏推荐
猜你喜欢

Matplotlib common operations

ThreadLocal giant pit! Memory leaks are just Pediatrics

ArcGIS batch export layer script

量化框架backtrader之一文读懂observer观测器

2022年最新贵州建筑八大员(机械员)模拟考试题库及答案

登录认证服务

PostGIS create spatial database

Pychar remotely connects to the server to run code

Pycharm远程连接服务器来跑代码

Chinese output of PostGIS console is garbled
随机推荐
Common controls and custom controls
Installation tutorial about origin2019
Hard (magnetic) disk (I)
Can wptx64 be uninstalled_ Which software of win10 can be uninstalled
One article of the quantification framework backtrader read observer
wptx64能卸载吗_win10自带的软件哪些可以卸载
一个快速切换一个底层实现的思路分享
Related knowledge of libsvm support vector machine
Knowledge about adsorption
Setup instance of layout manager login interface
Heap optimization dijkstra/hash table storage node number
【async/await】--异步编程最终解决方案
近期比较重要消息
《三体》摘录
'教练,我想打篮球!' —— 给做系统的同学们准备的 AI 学习系列小册
Notes: the 11th and 12th generation mobile versions of Intel support the native thunderbolt4 interface, but the desktop version does not
ArcGIS secondary development - arcpy delete layer
使用宝塔面板部署flask环境
在线牛人博主
Matplotlib common operations