Combination mode--Stock trading has been cut leeks? Come and try this investment strategy!

Primer

The stock market is very hot recently, Xiaoshuai watched the people around him make a lot of money in the stock market, he couldn't help but feel itchy, he was attracted by various news about getting rich by speculating in the stock market every day, and finally couldn't help but get into the stock market. After a sharp drop, it was no surprise that he became a leek, and finally became disheartened.

Fortunately, Xiaoshuai happens to have a friend who is good at investing. Lao Zhang, the technical director of an IT company, has an average return of more than 20% in recent years. Xiaoshuai decided to ask him for investment tips.

"Old Zhang, I heard that you have made a lot of money in the stock market in recent years, can you teach me, I also want to learn how to trade in stocks." Xiaoshuai asked Lao Zhang for advice.

Lao Zhang smiled slightly and said, "Okay, but investment is too complicated. If you ask me to teach you, you won't be able to start right away. Tell me what you want to achieve through investment first?"

portfolio

"To be honest, I have lost a lot of money in stocks recently. The risk of stocks is too great. Is there an investment strategy that can protect investors in any economic environment and allow everyone to obtain safe, stable and long-term returns? , and at the same time it is very simple, so even people who know the least about investing can use it?" Xiaoshuai asked eagerly.

"Really, a very famous investor Brown proposed an asset allocation method called 'The Permanent Portfolio' (The Permanent Portfolio), which just solved this problem."

Lao Zhang continued:

The permanent portfolio divides the funds to be invested into four equal parts: 25% stocks, 25% treasury bonds, 25% cash and 25% gold.

However, for a novice like you, it is not suitable to directly invest in individual stocks. I replace stocks with index funds, and replace treasury bonds with more flexible bond funds. Gold is just paper gold.

I transform the permanent portfolio: 25% index funds, 25% bond funds, 25% cash and 25% paper gold.

I drew the structure diagram of the investment portfolio, Xiaoshuai, aren't you a programmer? If I want to traverse each investment and calculate the total amount of investment, can I write it in code?
insert image description here

traverse files

Xiaoshuai said: "This is not difficult. In fact, this structure is very similar to the file system we often use. It is a tree structure. Calculating the total amount of funds is very similar to traversing files. Let's first see how to traverse directories and files. "
insert image description here
Directories are divided into folders and files, folders are branches, and files are leaf nodes. We can define an IBranch to represent the directory interface, and ILeaf to represent the file interface.

/**
 * 目录接口
 */
public interface IBranch {
    
    
    /**
     * 打印目录名
     * @param depth
     */
    void print(int depth);

    /**
     * 添加目录
     * @param branch
     */
    void add(IBranch branch);

    /**
     * 添加文件
     * @param leaf
     */
    void add(ILeaf leaf);

    /**
     * 获目录内容
     * @return
     */
    List<Object> getSubList();
}

/**
 * 目录实现类
 */
public class Branch implements IBranch{
    
    

    List<Object> branchList = new ArrayList<Object>();

    String name;
    public Branch(String name) {
    
    
        this.name = name;
    }

    @Override
    public void print(int depth) {
    
    
        System.out.println(String.join("", Collections.nCopies(depth, "--")) 
        + name);
    }

    @Override
    public void add(IBranch branch) {
    
    
        branchList.add(branch);
    }

    @Override
    public void add(ILeaf leaf) {
    
    
        branchList.add(leaf);
    }

    @Override
    public List getSubList() {
    
    
        return branchList;
    }
}

/**
 * 文件接口
 */
public interface ILeaf {
    
    
    /**
     * 打印文件名
     * @param depth
     */
    void print(int depth);
}
/**
 * 文件实现类
 */
public class Leaf implements ILeaf{
    
    

    String name;
    public Leaf(String name) {
    
    
        this.name = name;
    }

    @Override
    public void print(int depth) {
    
    
        System.out.println(String.join("", Collections.nCopies(depth, "--")) 
        + name);
    }
}

Construct directories and files, then print:

public class BuildBranch {
    
    

    public static void main(String[] args) {
    
    
        IBranch root = new Branch("根目录");

        IBranch firstLevelBranch1 = new Branch("1级目录1");
        ILeaf firstLevelBranch1File1 = new Leaf("1级目录1-文件1");
        ILeaf firstLevelBranch1File2 = new Leaf("1级目录1-文件2");
        firstLevelBranch1.add(firstLevelBranch1File1);
        firstLevelBranch1.add(firstLevelBranch1File2);
        // 把1级目录1添加到根目录
        root.add(firstLevelBranch1);

        IBranch firstLevelBranch2 = new Branch("1级目录2");
        ILeaf firstLevelBranch2File1 = new Leaf("1级目录2-文件1");
        firstLevelBranch2.add(firstLevelBranch2File1);
        // 把1级目录2添加到根目录
        root.add(firstLevelBranch2);

        IBranch secondLevelBranch1 = new Branch("2级目录1");
        ILeaf secondLevelBranch1File1 = new Leaf("2级目录1-文件1");
        ILeaf secondLevelBranch1File2 = new Leaf("2级目录1-文件2");
        secondLevelBranch1.add(secondLevelBranch1File1);
        secondLevelBranch1.add(secondLevelBranch1File2);
        // 把2级目录添加到1级目录
        firstLevelBranch1.add(secondLevelBranch1);

        root.print(0);
        // 遍历所有文件和文件夹
        printAll(root.getSubList(), 1);

    }

    /**
     * 遍历所有文件和文件夹
     * @param list
     * @param depth
     */
    public static void printAll(List<Object> list, int depth) {
    
    
        for(Object object : list) {
    
    
            if(object instanceof Leaf) {
    
    
                ((Leaf) object).print(depth);
            } else {
    
    
                ((Branch) object).print(depth);
                printAll(((Branch) object).getSubList(), depth + 2);
            }
        }
    }
}

Output result:

根目录
--1级目录1
------1级目录1-文件1
------1级目录1-文件2
------2级目录1
----------2级目录1-文件1
----------2级目录1-文件2
--1级目录2
------1级目录2-文件1

"Look, this is all right," Xiaoshuai smiled.

Lao Zhang saw the problem at a glance: You have two interfaces, IBranch and ILeaf, but you actually regard folders and files as two different things. When the client traverses, it needs to distinguish between folders and files. It must first determine the type of object in the program before proceeding with different operations.

In fact, folders and files are the relationship between the whole and part, that is, the relationship between the branches and leaves of the tree. Can we regard them as the same thing? A leaf is just a branch with no children, isn't it?
insert image description here
Lao Zhang continued: "Can you find a way to let the client not distinguish between folders and files, so that the client can operate branches and leaves in the same way? In this way, the client's call will be much simpler."

Xiaoshuai said: "I can't think of this right now, Lao Zhang, tell me quickly, how can I write it better?"

combination mode

"Aiming at this situation, there is a special design pattern called combination pattern, let us take a look together."

Composite mode: Organize a group of objects into a tree structure to represent the "part-whole" hierarchy, so that users have consistency in the use of individual objects and composite objects.

That is to say, the composite mode treats a single object and a composite object as the same thing. In the example above, a file is a single object, and a folder is a composite object.

Let's take a look at the class diagram:
insert image description here

traverse files

Now let's transform the above code with the combination mode:

/**
 * 组件类
 */
public abstract class Component {
    
    

    /**
     * 添加组件
     * @param
     */
    public void add(Component component) {
    
    
        throw new UnsupportedOperationException("不支添加操作");
    }

    /**
     * 删除组件
     * @param component
     */
    public void remove(Component component) {
    
    
        throw new UnsupportedOperationException("不支删除操作");
    }

    /**
     * 打印名称
     * @param depth
     */
    public abstract void print(int depth);
}
/**
 * 文件类
 */
public class File extends Component{
    
    

    String name;
    public File(String name) {
    
    
        this.name = name;
    }

    /**
     * 打印名称
     * @param depth
     */
    @Override
    public void print(int depth) {
    
    
        System.out.println(String.join("", Collections.nCopies(depth, "--")) 
        + name);
    }
}

/**
 * 目录类
 */
public class Directory extends Component{
    
    

    List<Component> componentList = new ArrayList<Component>();

    String name;
    public Directory(String name) {
    
    
        this.name = name;
    }

    /**
     * 添加组件
     * @param
     */
    @Override
    public void add(Component component) {
    
    
        componentList.add(component);
    }

    /**
     * 删除组件
     * @param component
     */
    @Override
    public void remove(Component component) {
    
    
        componentList.remove(component);
    }

    /**
     * 打印名称
     * @param depth
     */
    @Override
    public void print(int depth) {
    
    
        System.out.println(String.join("", Collections.nCopies(depth, "--")) 
        + name);
        // 递归打印子组件
        for (Component component : this.componentList) {
    
    
            component.print(depth + 2);
        }
    }
}
public class BuildDirectory {
    
    

    public static void main(String[] args) {
    
    
        Directory root = new Directory("root");

        Directory booksDirectory = new Directory("books");
        File coreJavaFile = new File("Java核心技术");
        File codeCompleteFile = new File("代码大全");
        booksDirectory.add(coreJavaFile);
        booksDirectory.add(codeCompleteFile);
        // books文件夹添加到根目录
        root.add(booksDirectory);

        Directory picturesDirectory = new Directory("pictures");
        File pictures1 = new File("照片1");
        File pictures2 = new File("照片2");
        File pictures3 = new File("照片3");
        picturesDirectory.add(pictures1);
        picturesDirectory.add(pictures2);
        picturesDirectory.add(pictures3);
        // 删除照片2
        picturesDirectory.remove(pictures2);
        // 把pictures文件夹添加到根目录
        root.add(picturesDirectory);

        Directory networkDirectory = new Directory("network");
        File computerNetworkingFile = new File("计算机网络:自顶向下方法");
        File tcpIpFile  = new File("TCP/IP详解");
        networkDirectory.add(computerNetworkingFile);
        networkDirectory.add(tcpIpFile);
        // 把network文件夹添加到books文件夹
        booksDirectory.add(networkDirectory);

        root.print(0);
    }
}

output:

root
----books
--------Java核心技术
--------代码大全
--------network
------------计算机网络:自顶向下方法
------------TCP/IP详解
----pictures
--------照片1
--------照片3

"Look, doesn't it look much simpler this way?" Old Zhang said.

Xiaoshuai thought for a while and said: "Conciseness is much more concise, but I always feel a little strange. Why do the add method and the remove method directly throw an exception?" Lao Zhang smiled and said:
insert image description here
You observe carefully, because add The method and the remove method are unique methods of the folder class. There are no such methods in the file class, but in order to increase the transparency of the client's use, that is, to make the folder and the file look the same in the eyes of the client , so that the folder class and the file class have the same method.

However, in order to prevent misoperation by the client, the add and remove methods are operated in the file class, so when we declare in the Component class, an exception is thrown directly, which is also a protection measure for the program. The folder class Directory will rewrite the add and remove methods in its own class to implement the functions of adding and deleting.

Xiaoshuai seemed to understand suddenly: " The so-called transparency is to let the component class Component include all operations of the branch and the leaf node at the same time, so that the client can regard the branch and the leaf node as the same thing, that is to say, an element Whether it is a branch or a leaf node is transparent to the client. "

Lao Zhang added: "You understand correctly, in order to achieve 'transparency', we lose certain 'safety', for example, when the client calls the add and remove methods on the leaf node, an exception will be thrown, but, If we emphasize 'safety', we will lose 'transparency', just like in the first example we need to use instanceof to distinguish different types in the program."
insert image description here

Lao Zhang went on to say, "Transparency and security cannot be combined. In the previous example, we chose transparency and gave up security. Similarly, when investing, low risk and high return cannot be combined. The permanent portfolio tends to control risks, in order to keep the principal, give up a little bit of high income, you can’t have it both ways.”

"Okay, now you use the combination mode to implement the code for calculating the total amount of the permanent combination."

"Okay, look at mine."

Calculate total portfolio amount

/**
 * 组件类
 */
public abstract class Component {
    
    

    /**
     * 添加组件
     * @param
     */
    public void add(Component component) {
    
    
        throw new UnsupportedOperationException("不支添加操作");
    }

    /**
     * 删除组件
     * @param component
     */
    public void remove(Component component) {
    
    
        throw new UnsupportedOperationException("不支删除操作");
    }

    /**
     * 打印名称
     * @param depth
     */
    public abstract void print(int depth);

    /**
     * 计算总金额
     */
    public abstract int countSum();
}
/**
 * 投资项目
 */
public class Project extends Component{
    
    

    String name;
    int price;
    public Project(String name, int price) {
    
    
        this.name = name;
        this.price = price;
    }

    /**
     * 打印名称
     * @param depth
     */
    @Override
    public void print(int depth) {
    
    
        System.out.println(String.join("", Collections.nCopies(depth, "--")) 
        + name + " 投资:" + price);
    }

    /**
     * 返回金额
     * @return
     */
    @Override
    public int countSum() {
    
    
        return price;
    }
}
/**
 * 投资品类
 */
public class Category extends Component{
    
    

    List<Component> componentList = new ArrayList<Component>();

    String name;
    public Category(String name) {
    
    
        this.name = name;
    }

    /**
     * 添加组件
     * @param
     */
    @Override
    public void add(Component component) {
    
    
        componentList.add(component);
    }

    /**
     * 删除组件
     * @param component
     */
    @Override
    public void remove(Component component) {
    
    
        componentList.remove(component);
    }

    /**
     * 打印名称
     * @param depth
     */
    @Override
    public void print(int depth) {
    
    
        System.out.println(String.join("", Collections.nCopies(depth, "--")) 
        + name);
        // 递归打印子组件
        for (Component component : componentList) {
    
    
            component.print(depth + 2);
        }
    }

    /**
     * 计算总金额
     * @return
     */
    @Override
    public int countSum() {
    
    
        int sum = 0;
        for (Component component : componentList) {
    
    
            sum += component.countSum();
        }
        return sum;
    }
}
public class BuildProject {
    
    

    public static void main(String[] args) {
    
    
        Category root = new Category("永久组合");

        Project cash = new Project("现金",25000);
        Project paperGold = new Project("纸黄金", 25000);
        root.add(cash);
        root.add(paperGold);

        Category indexFund = new Category("指数基金");
        Project hushen300 = new Project("沪深300",10000);
        Project zhongzheng500 = new Project("中证500",10000);
        Project chaungyeban = new Project("创业板指数",5000);
        indexFund.add(hushen300);
        indexFund.add(zhongzheng500);
        indexFund.add(chaungyeban);
        // 指数基金添加到永久组合中
        root.add(indexFund);

        Category bondFund = new Category("债券基金");
        Project hybridBondFund = new Project("混合债券基金", 15000);
        Project prueBondFund = new Project("纯债券基金", 10000);
        Project corporateonds = new Project("企业债券", 5000);
        bondFund.add(hybridBondFund);
        bondFund.add(prueBondFund);
        bondFund.add(corporateonds);
        // 企业债券风险太高,删掉
        bondFund.remove(corporateonds);
        // 把pictures文件夹添加到根目录
        root.add(bondFund);

        root.print(0);
        System.out.println("投资总金额:" + root.countSum());
    }
}

Output result:

永久组合
----现金 投资:25000
----纸黄金 投资:25000
----指数基金
--------沪深300 投资:10000
--------中证500 投资:10000
--------创业板指数 投资:5000
----债券基金
--------混合债券基金 投资:15000
--------纯债券基金 投资:10000
投资总金额:100000

"It's not bad!" Lao Zhang praised.

Summarize

Application scenarios of combination mode:

  • If you need to implement a tree-like object structure, you can use the Composite pattern.
  • Use this pattern if you want client code to treat simple and complex elements the same way.

Advantages of the composite pattern:

  • Easy to use, you can use polymorphism and recursion mechanism to use complex tree structures more conveniently.
  • Client code is simplified, clients can consistently work with a composite structure and individual objects, often users don't know (and don't care) whether they are dealing with individual objects or the entire composite structure.
  • Following the open-closed principle, you can add new elements to your application as part of the object tree without changing existing code.

Disadvantages of composite mode:

  • For classes with large functional differences, it will be more difficult to provide a common interface, which will increase the difficulty for the client to understand, and the client will easily call the wrong operation.

at last

Lao Zhang patted Xiaoshuai and said: According to this investment portfolio, risks can be well controlled, and good returns can be obtained. It is very suitable for a noob investment like you. You can also make some adjustments according to your actual situation. For example, the current Yu’e Bao is actually a currency fund, which has little risk and is very convenient to use. You can deposit cash in Yu’e Bao or other money funds and get a certain amount of money. income.

If you have a relatively high risk tolerance, you can appropriately increase the proportion of index funds, and lower the proportions of cash, paper gold, and bond funds. Investment is an art. There is no best, only the most suitable for you.

Also, we’d better use fixed investment to buy funds, such as buying 1,000 yuan a month, don’t buy it all at once, fixed investment can spread the risk well, and won’t let you buy at the highest point, after all, choose Time is difficult.

"Thank you, Zhang! Not only did I learn about investment today, but I also learned about design patterns, haha!" Xiaoshuai said happily.

Guess you like

Origin blog.csdn.net/zhanyd/article/details/115494405