当前位置: 首页 > article >正文

C#从零开始学习(封装(5)

本章所有的代码都放在
https://github.com/hikinazimi/head-first-Csharp

封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。在面向对象程序设计方法论中,封装是为了防止对实现细节的访问。

抽象和封装是面向对象程序设计的相关特性。抽象允许相关信息可视化,封装则使开发者实现所需级别的抽象。

C# 封装根据具体的需要,设置使用者的访问权限,并通过 访问修饰符 来实现。

封装意味着对另一个类隐藏信息,但是封装中的信息可以使用反射拿出来

SwordDamage游戏

本项目是一个计算伤害的程序

第一版

<Window x:Class="SwordDamage_WPF_Part_1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SwordDamage_WPF_Part_1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <CheckBox x:Name="flaming" Content="Flaming"
            HorizontalAlignment="Center" VerticalAlignment="Center"
            Checked="Flaming_Checked" Unchecked="Flaming_Unchecked"/>

        <CheckBox x:Name="magic" Content="Magic" Grid.Column="1" 
            HorizontalAlignment="Center" VerticalAlignment="Center"
            Checked="Magic_Checked" Unchecked="Magic_Unchecked" />

        <Button Grid.Row="1" Grid.ColumnSpan="2" Margin="20,10" 
            Content="Roll for damage" Click="Button_Click"/>

        <TextBlock x:Name="damage" Grid.Row="2" Grid.ColumnSpan="2" Text="damage"
               VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </Grid>
    
</Window>

在这里插入图片描述
下列是SwordDamage类
包含有基础伤害和火焰伤害,还有伤害倍率

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SwordDamage_WPF_Part_1
{
    class SwordDamage
    {

        public const int BASE_DAMAGE = 3;
        public const int FLAME_DAMAGE = 2;

        public int Roll;
        public decimal MagicMultiplier = 1M;
        public decimal FlameMultiplier = 0;
        public int Damage;

        public void CalculateDamage()
        {
            Damage = (int)(Roll * MagicMultiplier) + BASE_DAMAGE + FLAME_DAMAGE;
        }

        public void SetMagic(bool isMagic)
        {
            if (isMagic)
            {
                MagicMultiplier = 1.75M;
            }
            else
            {
                MagicMultiplier = 1M;
            }
            CalculateDamage();
        }
        public void SetFlaming(bool isFlaming)
        {
            CalculateDamage();
            if (isFlaming)
            {
                Damage += FLAME_DAMAGE;
            }
        }


    }
}

以下是游戏的逻辑关系,是有一定的Bug,通过思考错误原因,提升自己的能力

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SwordDamage_WPF_Part_1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    /// 
    public partial class MainWindow : Window
    {
        Random random = new Random();
        SwordDamage swordDamage = new SwordDamage();
        public MainWindow()
        {
            InitializeComponent();
            swordDamage.SetMagic(false);
            swordDamage.SetFlaming(false);
            RollDice();
        }

        public void RollDice()
        {
            swordDamage.Roll = random.Next(1, 7) + random.Next(1, 7) + random.Next(1, 7);
            DisplayDamage();

        }
        public void DisplayDamage()
        {
             damage.Text = "Rolled " + swordDamage.Roll + " for " + swordDamage.Damage + " HP"; ;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            RollDice();
        }

        private void Flaming_Checked(object sender, RoutedEventArgs e)
        {
            swordDamage.SetFlaming(true);
            DisplayDamage();
        }
        private void Flaming_Unchecked(object sender, RoutedEventArgs e)
        {
            swordDamage.SetFlaming(false);
            DisplayDamage();
        }

        private void Magic_Checked(object sender, RoutedEventArgs e)
        {
            swordDamage.SetMagic(true);
            DisplayDamage();
        }

        private void Magic_Unchecked(object sender, RoutedEventArgs e)
        {
            swordDamage.SetMagic(false);
            DisplayDamage();
        }
    }
}

该程序在我们点击Roll for damage时,伤害没有发生改变
观察代码可得在我们点击按钮后,调用Button_Click函数,没有从新计算数值
可以在计算时加上

       public void RollDice()
        {
            swordDamage.Roll = random.Next(1, 7) + random.Next(1, 7) + random.Next(1, 7);
            swordDamage.SetFlaming(flaming.IsChecked.Value);
            swordDamage.SetMagic(magic.IsChecked.Value);
            DisplayDamage();
        }

但是火焰的数值还是有问题
可以使用Debug.WriteLine打印信息

        public void CalculateDamage()
        {
            Damage = (int)(Roll * MagicMultiplier) + BASE_DAMAGE + FlamingDamage;
            Debug.WriteLine($"CalculateDamage finished: {Damage} (roll: {Roll})");
        }

通过调试我们可以看出
在这里插入图片描述
程序调用的顺序有问题,先调用了SetFlaming函数,这个应该最后调用.程序没有按照我们想要的方式运行

第二版

思考错误原因

  • 方法误用,调用的顺序不对
  • 设置Roll后,要立即计算伤害
  • 思考公共和私有方法
using System;
using System.Collections.Generic;
using System.Text;

namespace SwordDamage_WPF_Part_2
{
    class SwordDamage
    {
        private const int BASE_DAMAGE = 3;
        private const int FLAME_DAMAGE = 2;

        /// <summary>
        /// Contains the calculated damage.
        /// </summary>
        public int Damage { get; private set; }

        private int roll;

        /// <summary>
        /// Sets or gets the 3d6 roll.
        /// </summary>
        public int Roll
        {
            get { return roll; }
            set
            {
                roll = value;
                CalculateDamage();
            }
        }

        private bool magic;

        /// <summary>
        /// True if the sword is magic, false otherwise.
        /// </summary>
        public bool Magic
        {
            get { return magic; }
            set
            {
                magic = value;
                CalculateDamage();
            }
        }

        private bool flaming;

        /// <summary>
        /// True if the sword is flaming, false otherwise.
        /// </summary>
        public bool Flaming
        {
            get { return flaming; }
            set
            {
                flaming = value;
                CalculateDamage();
            }
        }
        /// <summary>
        /// Calculates the damage based on the current properties.
        /// </summary>
        private void CalculateDamage()
        {
            decimal magicMultiplier = 1M;
            if (Magic) magicMultiplier = 1.75M;

            Damage = BASE_DAMAGE;
            Damage = (int)(Roll * magicMultiplier) + BASE_DAMAGE;
            if (Flaming) Damage += FLAME_DAMAGE;
        }

        /// <summary>
        /// The constructor calculates damage based on default Magic
        /// and Flaming values and a starting 3d6 roll.
        /// </summary>
        /// <param name="startingRoll">Starting 3d6 roll</param>
        public SwordDamage(int startingRoll)
        {
            roll = startingRoll;
            CalculateDamage();
        }
    }
}

给改代码之后,在使用Roll时,可以观察到,会调用计算伤害的函数,计算伤害的函数是按照顺序计算的

        public int Roll
        {
            get { return roll; }
            set
            {
                roll = value;
                CalculateDamage();
            }
        }

而在计算伤害的函数中,按照顺序计算各个数值

        private void CalculateDamage()
        {
            decimal magicMultiplier = 1M;
            if (Magic) magicMultiplier = 1.75M;

            Damage = BASE_DAMAGE;
            Damage = (int)(Roll * magicMultiplier) + BASE_DAMAGE;
            if (Flaming) Damage += FLAME_DAMAGE;
        }

至此,我们就学习完了第五章,然后让我们复习一下本章讲了什么

  • 修正Bug之前思考导致的真正的原因
  • 如何思考修改Bug
  • 使用Debug.WriteLine跟踪错误信息
  • 封装的一些做法
  • 将程序逻辑封装好,防止被随意使用

http://www.kler.cn/news/363638.html

相关文章:

  • 梳理一下spring中,与message相关的知识点
  • AI自动生成PPT哪个软件好?智能生成PPT不再熬夜做课件
  • 【C++11】右值引用和移动语义
  • 【Linux】“echo $变量“ 命令打印变量值的底层原理
  • Python 应用可观测重磅上线:解决 LLM 应用落地的“最后一公里”问题
  • 鲸鱼优化算法(Whale Optimization Algorithm, WOA)原理与MATLAB例程
  • JAVA Maven 的安装与配置
  • redis 使用
  • 04. VSCODE:C/C++简捷项目专用配置
  • MMA: Multi-Modal Adapter for Vision-Language Models
  • 第1节 什么是鸿蒙系统
  • 基于匿名管道实现的进程池
  • 系统移植相关概念总结
  • 大数据-MySQL集群
  • 使用electron 打包构建cocosCreator 的window exe
  • 鸿蒙应用开发:数据持久化
  • windows 上编译ceres suitesparse
  • #Swift 下标 Subscript - Access the elements of a collection
  • 【C++指南】运算符重载详解
  • 【JAVA毕设】基于JAVA的酒店管理系统
  • Flink SQL+Hudi数据入湖与分析实践
  • Scala的reduce
  • 昆虫种类识别数据集昆虫物种分类数据集YOLO格式VOC格式 目标检测 机器视觉数据集
  • 牛客周赛64(C++实现)
  • 你真的了解Canvas吗--解密十二【ZRender篇】
  • 【AI创新】优化ChatGPT提示词Prompt设计:释放AI的无限潜能